【问题标题】:heap corruption detected after normal block crt detected that the application在正常块 crt 检测到应用程序后检测到堆损坏
【发布时间】:2021-07-10 09:38:24
【问题描述】:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;

class MyString
{
    char* str;
    int size;
public:
    MyString()
    {
        str = '\0';
        size = 1;
    }
    MyString(const char* const s)
        : str(new char[strlen(s)])
    {
        size = strlen(s) + 1;
        strcpy(str, s);
    }
    MyString(const MyString& another)
        : str(new char[another.size])
    {
        size = another.size;
        for (int i = 0; i < size; i++)
            str[i] = another.str[i];
    }
    ~MyString()
    {
        delete[] str;
    }
    void set(const char* st)
    {
        size = (int)strlen(st) + 1;
        str = new char[size];
        for (int i = 0; i < size; i++)
            str[i] = st[i];
    }
    bool isEqual(const MyString& other) const
    {
        if (size != other.size)
            return false;
        if (strcmp(str, other.str) == 0)
            return true;
        else
            return false;
    }
    void print() const
    {
        for (unsigned int i = 0; i < size; i++)
            cout << str[i];
        cout << endl;
    }
};

int main() {
    MyString strs[] = {
        MyString("C"),
        MyString(),
        MyString("Java")
    };
    strs[1].set("C++");

    const int arraySize = sizeof(strs) / sizeof(MyString);

    const MyString target("Java");
    for (int i = 0; i < arraySize; i++) {
        const MyString str(strs[i]); // copy constructor
        if (str.isEqual(target)) {
            cout << "[" << i << "]: ";
            str.print();
            break;
        }
    }
    for (const MyString& str : strs) {
        str.print();
    }
}

在 dev c++ 中它正在工作并且没有任何警告,但在 Visual Studio 2019 中,出现了“在正常块 crt 检测到应用程序后检测到堆损坏”之类的警告。我不知道有什么问题。

当我调试我的代码时,它在主要功能完成之前成功运行。当析构函数工作时,出现了警告。

请帮帮我:)

【问题讨论】:

    标签: c++


    【解决方案1】:

    您的默认构造函数不应使用最新的 GCC 编译器进行编译,您只能将 NULLnullptr 分配给指针

      MyString() {
        str = nullptr;
        size = 0;
      }
    

    这个构造函数需要一个额外的1字节来分配内存,这样就可以避免缓冲区溢出。

      MyString(const char* const s) : str(new char[strlen(s) + 1]) {
        size = strlen(s) + 1;
        strncpy(str, s, size);
      }
    

    strncpystrcpy 的更安全的替代品,我建议你使用这个。

    您还需要为operator= 添加实现,否则一旦您使用operator= 复制对象,编译器生成的会导致内存泄漏。

      MyString& operator=(const MyString& another) {
        if (&another == this) return *this;
        delete[] str;
        str = new char[another.size];
        size = another.size;
        // better to use strncpy here
        for (int i = 0; i < size; i++) str[i] = another.str[i];
        return *this;
      }
    

    question 中讨论了类似的字符串实现,您也可以参考那里的代码。

    Demo

    【讨论】:

    • ahhhhhhh yayyyy 非常感谢。我使用初始化器 str(new char[strlen(s) + 1]) 在 MyString(const char* const s) 构造函数中更正了我的代码。这是一个简单的错误...非常感谢,祝您有愉快的一天! -来自韩国学生:)
    • @iamianpark 很高兴听到这个消息!
    【解决方案2】:

    一个问题是默认构造函数中成员的初始化:

    str = '\0';
    size = 1;
    

    字符文字'\0 等于零,等于一个空指针。该分配相当于:

    str = nullptr;
    

    然而你还是说字符串的大小是1,这是错误的,因为没有字符串,大小应该为零。


    另一个(可能是您的问题的罪魁祸首)问题是,在您的构造函数 MyString(const char* const s) 中,您使用 strlen 来获取 C 样式的长度分配的空终止字符串,但您忘记了strlen 不计算空终止符。

    这意味着分配将太小,当您使用strcpy 复制字符串时,它会将空终止符写入您分配的内存范围之外。


    此外,您在其他地方计算空终止符,并实际设置大小以包含空终止符(即使在 MyString(const char* const s) 构造函数中)。这与大小不包括终止符的字符串的正常 C++ 语义背道而驰。

    这可能会导致进一步的问题,例如在您实际打印空终止符的 print 函数中。

    【讨论】:

    • 非常感谢!我还在构造函数 MyString(const char* const s) 处更正了我的代码: str(new char[strlen(s) + 1]) 像这样!我认为这个初始化程序是主要问题。感谢您的好评,祝您有美好的一天! -来自韩国
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-12
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多