【问题标题】:Unknown crash when using dynamic char array after several times多次使用动态字符数组时发生未知崩溃
【发布时间】:2014-02-26 17:27:01
【问题描述】:

在做动态内存的时候,导致程序崩溃的主要原因是什么?

我有一个类,在 .h 文件中定义了以下公共指针:

char *data;

我的程序有一个 main 函数,我在其中按顺序创建这个类的对象,在这个创建过程中我做了内存部分:

data = new char[dataSize];

主函数,执行一次(对象被创建 10 次)完美运行。但是,当我再次运行 main 函数(没有关闭程序)时,指令 data = new char[dataSize] 会导致程序崩溃(执行突然结束,所以我无法调试或查看任何东西)。

顺便说一句,每次创建对象时指针都会初始化为 NULL(在内存部分之前)。

这是代码。首先是 main 函数,它使用不同的对象执行了 20 次:

CBinFileHwd validEpsData1;

validEpsData.loadFile(lpcTheFile3,dwFileSize,FT_BIT);

所以函数的下一行将与上面相同,但不是validEpsData1,而是validEpsData2,最多18次(validEpsData17)。

类代码(.c):

CBinFileHwd::CBinFileHwd()
{
    status = FILE_NOT_LOADED;
    fileType = FT_UNKNOWN;
    data = NULL;
    currentPos = 0;
    dataSize = 0;
}
CBinFileHwd::~CBinFileHwd()
{
    if (data!=NULL) {
        delete [] data;
        data= NULL;
    }
    fileType = FT_UNKNOWN;
    status = FILE_NOT_LOADED;
}
int CBinFileHwd::loadFile(const char *fileName, const unsigned long int &maxSize, const E_FILE_TYPE &fType)
{
    // Open input file
    int fd = open(fileName,O_RDONLY | O_BINARY);
    if (fd < 0) {
        char  logString[1024];
        sprintf(logString,"Error opening file %s",fileName);
        logMessage(logString, false, false, false);

        fileType = FT_UNKNOWN;
        status = FILE_NOT_LOADED;
        return -1;
    }

    dataSize = lseek(fd,0,SEEK_END);
    lseek(fd,0,SEEK_SET);

    if (maxSize < dataSize) {
        dataSize = maxSize;
    }
    data = new char[dataSize];
    unsigned long int dataRead = 0;

    while (dataRead < dataSize){
        dataRead += read(fd, &data[dataRead], BLOCK_SIZE);
    }
    // Close file
    close(fd);

    status = FILE_LOADED;
    fileType = fType;
    if (maxSize != dataSize) {
        return 1;
    }else{
        return 0;
    }

}

类代码(.h):

typedef enum{FT_BIT,FT_INT,FT_DOUBLE, FT_UNKNOWN} E_FILE_TYPE;

class CBinFileHwd
{
    private:
        static const int BLOCK_SIZE = 4096;
        typedef enum{FILE_NOT_LOADED, FILE_LOADED} E_STATUS;
        E_STATUS status;
        E_FILE_TYPE fileType;
        char *data;
        unsigned long int currentPos;
        unsigned long int dataSize;
    public:

        CBinFileHwd();
        ~CBinFileHwd();
    int loadFile(const char *fileName, const unsigned long int &maxSize, const E_FILE_TYPE &fType);
};

【问题讨论】:

  • 我相信您需要发布更多代码。例如,您的主要功能。
  • 你删除内存吗?如果是,你使用delete[]吗?
  • 我敢打赌这是由于某种原因导致堆栈损坏。没有看到代码就无法确定。
  • 你说的再次运行main函数(不关闭程序)是什么意思
  • @cuartango,我们也不知道。发布代码以获得答案。

标签: c++ pointers memory char


【解决方案1】:

这可能是因为:

  1. 由于为此类编写的复制构造函数和赋值运算符不正确而导致双重释放。因此,多个对象可能指向相同的动态内存分配。如果您的输入数据大小不超过 128 字节长度(这是您的分配大小),则构造函数和析构函数看起来没问题。

  2. 这也可能是因为您的程序中的堆内存损坏,而这段代码可能只是其他地方实际损坏的受害者/后效应。

但是,一旦您发布您的代码,我们可能会更好地找出崩溃的原因。

【讨论】:

    【解决方案2】:

    由于我上面的回答中提到的第 1 点,您的程序看起来正在崩溃。

    似乎还有一个内存泄漏问题,因为“数据”是您的类的成员变量,一旦您多次调用 loadFile() 函数,数据就会被新的内存地址覆盖。这也是你代码中的一个大问题。

    您可能希望在分配“数据”内存之前进行检查。

    int CBinFileHwd::loadFile
    {
     ...................
     if(data != nullptr) {
       data = new char[dataSize];
    }
        unsigned long int dataRead = 0;
    ..........................
    }
    

    【讨论】:

    • 我同意你的观点,看来问题是内存被覆盖了。我尝试将 delete [] 放在 loadFile 函数的末尾(而不是在析构函数中),但我没有收到错误,但程序没有按预期执行。有没有办法删除内存?
    • @cuartango,我认为您应该首先检查“数据”是否为nullptr。如果它不是 nullptr,那么你应该像往常一样分配。如果它等于nullptr,那么你应该先删除然后分配。如果您知道最大值,那么您可以在构造函数中分配内存,并可以在此类的任何成员函数中重用它。在析构函数的最后,您可以像现在一样删除内存。我认为这是最好的,你可以在现有的实现中做到这一点。但是,如果可能,我也建议您尝试在 iostream/string 类中重新实现您的逻辑。
    • 我已经尝试过你所说的但仍然崩溃。我发现如果我不使用任何删除,程序就可以工作。似乎 Borland 内部的自动析构函数(它是 muy 编译器)正在删除保留的内存。我也确信这一点,因为在 Windows 任务管理器中,当我执行这部分程序时,进程中的内存现在正在上升。
    • @cuartango,没有编译器会自动删除 C++ 中的原始指针的内存。程序需要注意内存管理。任务管理器不会立即开始显示内存使用量的上升,因为它取决于许多其他因素(提交/私有)。它不是堆内存分配和任务管理器信息的直接映射。因此,即使您的程序有效,不删除内存也不是正确的方法。对于现实世界的软件来说,内存泄漏是一个非常讨厌和复杂的问题。您可以使用 WinDBG/Pageheap 来识别程序中实际的内存溢出。
    • 你是对的,在其他处决中我仍然有错误。感谢关于WinDBG/Pageheap的提示,我会尝试找到内存错误。
    【解决方案3】:

    试试:

    dataRead += read(fd, (data+dataRead), BLOCK_SIZE);

    您是否不小心将 18 次都分配给同一个变量“validEpsData”,在这种情况下,您会出现内存泄漏。你在哪里声明了这个变量?

    validEpsData.loadFile(lpcTheFile3,dwFileSize,FT_BIT);
    

    应该是:

    validEpsData1.loadFile(lpcTheFile3,dwFileSize,FT_BIT);
    ......
    validEpsData18.loadFile(lpcTheFile3,dwFileSize,FT_BIT);
    

    在您超出 main() 范围或退出程序之前,不会调用析构函数

    【讨论】:

    • 正如您所说,我已经将 validEpsData 分配给不同的变量。最后我改变了读取文件的方式。不过还是谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-31
    • 1970-01-01
    • 2020-02-18
    相关资源
    最近更新 更多