【问题标题】:Heap corruption when freeing 2D dynamic array释放 2D 动态数组时堆损坏
【发布时间】:2013-09-02 02:36:33
【问题描述】:

我有一个简单的程序来填充二维动态字符数组。分配照常进行。我的问题依赖于释放数组。我在 VC++ 2008 上使用纯 C。

这是我分配和初始化数组时的一段代码:

char** messsages = (char**)malloc(5*sizeof(char*));
initValorArrayMsgs(messsages, 5);

insertMsgToArray(5, messsages , "Test message.");

void insertMsgToArray(int totalLines, char** msgsArray, const char* msgToInsert)
{
    int line = 0;
    int size= strlen(msgToInsert);

    for(; line < totalLines; line ++)
    {
        if(strlen(msgsArray[line ]) == 0)
        {
            msgsArray[line ] = (char*)malloc(sizeof(char) * size);
            strcpy(msgsArray[line], msgToInsert);
            break;
        }
    }
}

这是我释放数组的代码

void freeArrayMsgs(char** arry, int lines)
{
    int i = 0;
    for(; i < lines; i++)
    {
        if(strlen(arry[i]) == 0){
            break;
        }
        free(arry[i]);
    }
    free(arry);
}

当程序尝试释放第一个数组时,会引发堆损坏异常。

阅读一些关于 SO 的帖子,我正确地释放了我的数组。那么,为什么我会收到 hep 损坏异常?

【问题讨论】:

  • msgsArray[line ] = (char*)malloc(sizeof(char) * size); 需要有 (size+1) 而不是 size 以容纳字符串的空终止符。附带说明一下,为什么不将循环初始化程序放在for 循环中呢?比如for ( i = 0; i &lt; lines; i++ )而不是单独做i = 0;和做for ( ; i &lt; lines; i++ )?
  • 和上面的bug一样,注意不要把malloc的结果转换成C语言。
  • 大家的回复很有帮助。
  • @PaulR 非常有趣的资源。

标签: c arrays malloc free


【解决方案1】:

我突然想到了两件事:

  1. freeArrayMsgs 的内部逻辑似乎很可疑:在第一个 NULL 指针上,它停止循环。

     for ( ;  i < lines;  i++)  
     {  
         if (strlen (arry[i]) == 0)  
             break;  
         free (arry[i]);  
     }
    

    也许没关系,但如果 lines 是有史以来使用的最大值,那么获取它们可能很重要。请注意,即使释放 NULL 指针也完全没问题——这样做是无操作的。

  2. 如果代码重用了指针,它真的应该在 free() 之后将它们清空。如果我看到的那段代码所暗示的相同理念在整个代码中仍然存在,那么您可能正在重用一个已释放的指针,因为存储的指针不是 NULL。这很容易解决:

    for ( ;  i < lines;  i++)  
    {  
        free (arry[i]);  
        arry[i] = NULL;  
    }
    

【讨论】:

  • 从快速播放看来,SO 不喜欢列表元素中的代码格式 - 我删除了您的 1. 和 2. 并且代码格式开始工作。
  • @wallyk 你只需要添加更多缩进。
  • @MarkHurd 我插入了中断,因为我不想删除任何东西,而是分配的内存。好的,我忘了在那之后放空。但问题仍然存在。
  • 我只是更正了缩进以使格式看起来正确。您可能想在这里@comment 给其他人。
【解决方案2】:

几件事:

  • 您需要malloc(size + 1) 以适应空终止符。
  • 没有必要做sizeof(char)-sizeof是根据char定义的,所以永远是1。
  • 您不应该转换 malloc 的结果 - 这是不必要的,并且可能会隐藏问题。
  • 由于msgsArray没有初始化,所以不能保证strlen(msgsArray[line]) == 0。事实上,它可能不会。如果您希望这是真的,请使用 calloc 而不是 malloc
  • 一般来说,使用strncpy 而不是strcpy - 更安全。
  • 与其使用strlen,不如将​​char*s 初始化为null 并检查null。如果第一个 msgToInsert 是一个空字符串,但其余的是真正的字符串怎么办?您的代码将退出循环,因为 strlen(msgs[0]) == 0,而检查 null 会解决问题。

【讨论】:

  • 已解决,堆损坏是因为我缺少适合空终止符。切入点马特。
猜你喜欢
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 2015-09-30
  • 1970-01-01
  • 2015-10-06
  • 1970-01-01
相关资源
最近更新 更多