释放动态二维数组在 C 中无法正常工作
Freeing dynamic 2D array not working as expected in C
当我 运行 代码如下:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int i, count = 0x09;
int sizei = 5, sizej = 2;
int **ary = malloc (sizei * sizeof **ary);
for (i = 0; i < sizei; i++) {
*(ary + i) = malloc (sizej * sizeof *(ary + i));
**(ary + i) = ++count;
printf (" %2d |%p| +%x+ \n", i, (ary + i), *(*(ary + i)));
}
puts("----");
for (i = sizei - 1; i >= 0; i--) {
printf (" %2d |%p| +%x+ \n", i, (ary + i), *(*(ary + i)));
free (*(ary + i));
}
puts("----");
free (ary);
return 0;
}
我希望前半部分会创建一个二维动态整数数组,称为 ary
(即指向动态分配的指针数组的指针,每个指针都指向一个动态分配的整数数组)。每个数组 **(ary + i)
的第 0 个元素将被递归分配 count
.
的当前值
后半部分将反向迭代,释放 ary
的每个元素,然后释放 ary
本身。
这似乎工作正常,直到我尝试释放 *(ary + 0)
,此时我得到双重释放/损坏错误。我已经包含了输出。
0 |0x1d6f010| +a+
1 |0x1d6f018| +b+
2 |0x1d6f020| +c+
3 |0x1d6f028| +d+
4 |0x1d6f030| +e+
----
4 |0x1d6f030| +e+
3 |0x1d6f028| +d+
2 |0x1d6f020| +c+
1 |0x1d6f018| +b+
0 |0x1d6f010| +1d6f0b0+
*** Error in `./a.out': double free or corruption (out): 0x0000000001d6f030 ***
我很好奇为什么 ary
的第 0 个元素的第 0 个元素(即 *(*(ary + 0) + 0))
或只是 **ary
)变成了一些内存地址(只是略微)了一旦它离开第一个循环,这个二维数组所占用的范围。
如果我摆脱第二个循环并尝试直接释放 ary
而没有首先释放它的任何元素,我会得到类似的东西:
0 |0x1d6f010| +a+
1 |0x1d6f018| +b+
2 |0x1d6f020| +c+
3 |0x1d6f028| +d+
4 |0x1d6f030| +e+
----
*** Error in `./a.out': free(): invalid next size (fast): 0x0000000001d6f010 ***
我不明白我在这里做错了什么。使用数组符号会有所不同吗?如果可能的话,我需要任何解决方案来让每个数组的动态长度独立于 ary
的其余元素的长度。 ary
的数字元素在编译时也不一定是已知的。如果相关的话,我正在使用 gcc 4.9。
问题 1
int **ary = malloc (sizei * sizeof **ary);
等同于
int **ary = malloc (sizei * sizeof int);
如果 sizeof
指针在您的系统中小于 sizeof(int)
,您最终会越界访问内存。
您需要使用:
int **ary = malloc (sizei * sizeof *ary);
或
int **ary = malloc (sizei * sizeof(int*));
问题2
*(ary + i) = malloc (sizej * sizeof *(ary + i));
需要
*(ary + i) = malloc (sizej * sizeof **(ary + i));
或
*(ary + i) = malloc (sizej * sizeof int);
或
ary[i] = malloc (sizej * sizeof *ary[i]);
或
ary[i] = malloc (sizej * sizeof int);
ari
是指向指针数组的指针 a,所以元素的大小是指针。在您的代码中,您使用 sizeof **ary
这是一个 int
int **ary = malloc (sizei * sizeof **ary);
每个指向 int
元素数组的指针。在这些指针的 malloc 中,您使用 sizeof *(ary+i)
这是指向 int
的指针
*(ary + i) = malloc (sizej * sizeof *(ary + i));
sizeof(int) 并不总是与 sizeof(int*) 相同。事实上,在大多数 64 位系统上,我怀疑你使用的是 sizeof(int)==4 和 sizeof(int*)==8.
我的猜测是你正在使用这样的系统,因此,你没有为主 ari
指针分配足够的内存,并且你正在用值溢出它,破坏关键内存的内容管理数据,因此未来的 malloc() 和 free() 调用很可能完全失败。
当我 运行 代码如下:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int i, count = 0x09;
int sizei = 5, sizej = 2;
int **ary = malloc (sizei * sizeof **ary);
for (i = 0; i < sizei; i++) {
*(ary + i) = malloc (sizej * sizeof *(ary + i));
**(ary + i) = ++count;
printf (" %2d |%p| +%x+ \n", i, (ary + i), *(*(ary + i)));
}
puts("----");
for (i = sizei - 1; i >= 0; i--) {
printf (" %2d |%p| +%x+ \n", i, (ary + i), *(*(ary + i)));
free (*(ary + i));
}
puts("----");
free (ary);
return 0;
}
我希望前半部分会创建一个二维动态整数数组,称为 ary
(即指向动态分配的指针数组的指针,每个指针都指向一个动态分配的整数数组)。每个数组 **(ary + i)
的第 0 个元素将被递归分配 count
.
后半部分将反向迭代,释放 ary
的每个元素,然后释放 ary
本身。
这似乎工作正常,直到我尝试释放 *(ary + 0)
,此时我得到双重释放/损坏错误。我已经包含了输出。
0 |0x1d6f010| +a+
1 |0x1d6f018| +b+
2 |0x1d6f020| +c+
3 |0x1d6f028| +d+
4 |0x1d6f030| +e+
----
4 |0x1d6f030| +e+
3 |0x1d6f028| +d+
2 |0x1d6f020| +c+
1 |0x1d6f018| +b+
0 |0x1d6f010| +1d6f0b0+
*** Error in `./a.out': double free or corruption (out): 0x0000000001d6f030 ***
我很好奇为什么 ary
的第 0 个元素的第 0 个元素(即 *(*(ary + 0) + 0))
或只是 **ary
)变成了一些内存地址(只是略微)了一旦它离开第一个循环,这个二维数组所占用的范围。
如果我摆脱第二个循环并尝试直接释放 ary
而没有首先释放它的任何元素,我会得到类似的东西:
0 |0x1d6f010| +a+
1 |0x1d6f018| +b+
2 |0x1d6f020| +c+
3 |0x1d6f028| +d+
4 |0x1d6f030| +e+
----
*** Error in `./a.out': free(): invalid next size (fast): 0x0000000001d6f010 ***
我不明白我在这里做错了什么。使用数组符号会有所不同吗?如果可能的话,我需要任何解决方案来让每个数组的动态长度独立于 ary
的其余元素的长度。 ary
的数字元素在编译时也不一定是已知的。如果相关的话,我正在使用 gcc 4.9。
问题 1
int **ary = malloc (sizei * sizeof **ary);
等同于
int **ary = malloc (sizei * sizeof int);
如果 sizeof
指针在您的系统中小于 sizeof(int)
,您最终会越界访问内存。
您需要使用:
int **ary = malloc (sizei * sizeof *ary);
或
int **ary = malloc (sizei * sizeof(int*));
问题2
*(ary + i) = malloc (sizej * sizeof *(ary + i));
需要
*(ary + i) = malloc (sizej * sizeof **(ary + i));
或
*(ary + i) = malloc (sizej * sizeof int);
或
ary[i] = malloc (sizej * sizeof *ary[i]);
或
ary[i] = malloc (sizej * sizeof int);
ari
是指向指针数组的指针 a,所以元素的大小是指针。在您的代码中,您使用 sizeof **ary
这是一个 int
int **ary = malloc (sizei * sizeof **ary);
每个指向 int
元素数组的指针。在这些指针的 malloc 中,您使用 sizeof *(ary+i)
这是指向 int
*(ary + i) = malloc (sizej * sizeof *(ary + i));
sizeof(int) 并不总是与 sizeof(int*) 相同。事实上,在大多数 64 位系统上,我怀疑你使用的是 sizeof(int)==4 和 sizeof(int*)==8.
我的猜测是你正在使用这样的系统,因此,你没有为主 ari
指针分配足够的内存,并且你正在用值溢出它,破坏关键内存的内容管理数据,因此未来的 malloc() 和 free() 调用很可能完全失败。