释放 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 数组 - 检测到堆损坏的主要内容,如果未能解决你的问题,请参考以下文章