释放 2D 数组 - 检测到堆损坏

Posted

技术标签:

【中文标题】释放 2D 数组 - 检测到堆损坏【英文标题】:Freeing 2D array - Heap Corruption Detected 【发布时间】:2014-04-27 19:52:28 【问题描述】:

编辑:对不起,我忘了说这是在 VS2013 中编码的。

我有一个全局声明的结构:

typedef struct data //Struct for storing search & sort run-time statistics.

    int **a_collision;
 data;

data data1;

然后我分配我的内存:

data1.a_collision = (int**)malloc(sizeof(int)*2);   //Declaring outer array size - value/key index.
for (int i = 0; i < HASH_TABLE_SIZE; i++)   
    data1.a_collision[i] = (int*)malloc(sizeof(int)*HASH_TABLE_SIZE);   //Declaring inner array size. 

然后我初始化所有元素:

//Initializing 2D collision data array.
for (int i = 0; i < 2; i++)
for (int j = 0; j < HASH_TABLE_SIZE; j++)
    data1.a_collision[i][j] = NULL;

最后,我希望释放内存(失败)。我已经尝试遵循 SO 上给出的一些答案,但没有成功。

free(data1.a_collision);
for (int i = 0; i < HASH_TABLE_SIZE; i++)
    free(data1.a_collision[i]);

在第一个空闲语句中给出了检测到堆损坏的错误。有什么建议吗?

【问题讨论】:

(int**)malloc(sizeof(int)*2) 看起来不对。 how to allocate memory for two 2d array (您的其他问题)您对free 的调用顺序错误。你不能释放一个外部数组然后释放它的元素。太晚了,已经没有元素了。 【参考方案1】:

您的代码中有多个错误。如何为二维数组分配内存以及一些拼写错误在逻辑上是错误的。

从代码“外部数组大小 - 值/键索引”中的注释来看,您似乎想要为“2 * HASH_TABLE_SIZE”大小的二维数组分配内存,而从代码中的 for 循环中断条件“i

分配内存:

假设您想为“2 * HASH_TABLE_SIZE”分配内存,您可以将相同的概念应用于不同的维度。

维度“2 * HASH_TABLE_SIZE”表示两行和 HASH_TABLE_SIZE 列。正确的分配步骤如下:

step-1:首先创建一个长度等于行数的 int 指针数组。

data1.a_collision =  malloc(2 * sizeof(int*)); 
//                   2 rows ^             ^ you are missing `*` 

这将创建两个大小的 int 指针 (int*) 数组,在外部数组分配的代码中,您已为两个 int 对象分配了内存为2 * sizeof(int),而您需要内存来存储地址。您需要分配的总内存字节数应为2 * sizeof(int*)(这是一个糟糕的拼写错误)。

你可以把上面的分配想象成:

                      343  347  
                     +----+----+
data1.a_collision---►| ?  | ?  |
                     +----+----+
    ? - 表示垃圾值,malloc 不初始化分配内存 分配了两个内存单元,每个可以存储int的地址 在图片中我假设 int* 的大小为 4 个字节。

此外,您应该注意到我没有对 malloc 函数返回的地址进行类型转换,因为它是隐式类型转换的 void* 是通用的,可以分配给任何其他类型的指针类型(实际上在 C 中我们应该避免类型转换,您应该阅读更多来自Do I cast the result of malloc?)。

现在步骤-2:为每行分配内存作为数组中所需的长度列数,即= HASH_TABLE_SIZE。所以你需要循环行数(不是 HASH_TABLE_SIZE)来为每一行分配数组,如下:

for(int i = 0; i < 2; i++)  
  //            ^^^^  notice   
  data1.a_collision[i] = malloc(HASH_TABLE_SIZE * sizeof(int)); 
  //                                                    ^^^^^

现在,您将在每一行中为长度为 HASH_TABLE_SIZE 的整数数组存储 int,您需要内存字节 = HASH_TABLE_SIZE * sizeof(int)。你可以把它想象成:

图表

        data1.a_collision = 342
            |  
            ▼                       201   205   209    213  
        +--------+                +-----+-----+-----+-----+
 343    |        |                |  ?  |  ?  |  ?  | ?   |  //for i = 0
        |        |-------|        +-----+-----+-----+-----+
        | 201    |       +-----------▲
        +--------+                  502   506  510    514
        |        |                +-----+-----+-----+-----+
 347    |        |                |  ?  |  ?  |  ?  | ?   |  //for i = 1
        | 502    |-------|        +-----+-----+-----+-----+
        +--------+       +-----------▲

   data1.a_collision[0] = 201
   data1.a_collision[1] = 502

在图片中我假设 HASH_TABLE_SIZE = 4 并且 int 的大小 = 4 字节,注意地址的值a

现在这些是正确的分配步骤。

释放内存:

否则分配你的释放步骤是错误的!

请记住,一旦您在某个指针上调用了 free,您就无法访问该指针(也可以通过其他指针访问 pr 内存),这样做会调用未定义的行为——这是一个可以在运行时检测到的非法内存指令,可能会导致——还检测到分段错误或堆损坏。

正确的释放步骤与分配相反:

for(int i = 0; i < 2; i++)
    free(data1.a_collision[i]); // free memory for each rows
free(data1.a_collision); //free for address of rows.

此外,这是为二维数组分配内存的一种方法,就像您尝试做的那样。但是有更好的方法可以连续为完整的 2D 数组分配内存,您应该阅读"Allocate memory 2d array in function C"(对于这个链接的答案,我还给出了如何为 3D 数组分配内存的链接)。

【讨论】:

@GeorgeLoman 欢迎您。您还应该学习如何分配连续内存。【参考方案2】:

这是一个开始:

您的“外部数组”有两个整数的空间,而不是两个指向整数的指针。

HASH_TABLE_SIZE 是否等于 2?否则,您的第一个 for 循环将写入您刚刚分配的数组之外。

【讨论】:

其实有多个错误。 OP 不知道如何为 2D 数组分配内存。 @GrijeshChauhan:是的。我同意。感谢您的评论。 感谢您提供有意义的建议,现在可以使用了。我没有意识到我必须为指向整数的指针声明空间,但不正确的数组范围是一个明显的错误。我还发现以下链接很有用:annigeri.in/2011/11/dynamic-two-dimensioned-arrays-in-c.html @GeorgeLoman 这不是一个很好的参考,请阅读这个而不是23.2: Dynamically Allocating Multidimensional Arrays【参考方案3】:

有几个问题:

    第一次分配不正确,你应该分配一个 (int *) 的数组:

     #define DIM_I 2
     #define DIM_J HASH_TABLE_SIZE
     data1.a_collision = (int**)malloc(sizeof(int*)*DIM_I);
    

    第二个不再正确:

     for (int i = 0; i < DIM_I; i++)
       data1.a_collision[i] = (int*)malloc(sizeof(int)*DIM_J);
    

    释放内存时,必须按 LastInFirstOut 顺序释放:

     for (int i = 0; i < DIM_I; i++)
         free(data1.a_collision[i]);
     free(data1.a_collision);
    

【讨论】:

欢迎来到“Stack Overflow”,我们在这里教书和帮助,而不仅仅是做别人的工作。无法解释的代码不是很有帮助,也不是很好的答案。

以上是关于释放 2D 数组 - 检测到堆损坏的主要内容,如果未能解决你的问题,请参考以下文章

字符串的动态数组,但我检测到堆损坏

在 dll 导出期间块之前检测到堆损坏

检测到 glibc - 在 C 程序中释放(int ** 类型)时出现双重释放或损坏消息

在 C++ 中检测到堆损坏错误

检测到堆损坏 - 仅限 iPhone 5S

仅在一定限度内释放 2D 指针数组的内存