在C中释放()malloc的二维数组的最佳方法

时间:2009-10-14 18:10:37

标签: c arrays memory pointers free

假设我有一个二维数组,它是用这样的东西创建的,

char **foo = (char **) malloc(height * sizeof(char *));
for(i = 0; i <= height; i++) 
    foo[i] = (char *) malloc (width * sizeof(char *));

首先,这是创建像这样的数组的正确方法吗?这里的问题是'height'和'width'是在运行时设置的东西。

这似乎有效,但这是释放这个2D阵列的最佳策略。 免费(funge)听起来不对。通过这里的其他帖子,我想我会逐个免费每个行?

我确实尝试过这样的事情,

for (height = 0; height < ip_ptr->funge_height; height++) {
    free(funge[height]);
} 
free(funge)

然而,这给了我一个双重自由指针异常。这是不是意味着,我不需要管理这段记忆?我的印象是,对于每个malloc的内存,我们应该调用free()。

9 个答案:

答案 0 :(得分:8)

由于所有'行'都是相同的大小,你可以用malloc(height * width * sizeof (char *))一次性地分配它(你是否正在创建一个char的二维数组还是一个不完全清楚{2}数组char *)。您可以使用乘法来计算适当的索引(即foo[i][j]变为foo + i * height + j),

free()同样地,只需一个电话。

答案 1 :(得分:8)

在for循环中,您使用i <= height;代替i < height;。因此,您正在写入无效的内存位置,并且代码的行为变得不可预测。

答案 2 :(得分:7)

第二个分配应该是:

foo[i] = (char *) malloc (width * sizeof(char));

您在分配时也会循环height+1次。

除此之外,这两个片段似乎对我而言,所以错误应该在其他地方。

如果数组只被分配为一大块内存,那么你只需要释放一次。

char **foo = (char **) malloc(height * sizeof(char *));
*foo = malloc(height * width * sizeof(char))
for (int i = 1; i < height; i++) {
  foo[i] = *foo + i*width;
}
//and you just do 2 frees
free(*foo);
free(foo);

答案 3 :(得分:3)

分配的机制是可以的(尽管在分配循环中应该使用sizeof(char)而不是sizeof(char *);如果宽度和高度是运行时值,则要分配字符串。

你应该为每个malloc()调用free()一次的印象基本上是正确的(像calloc()和realloc()之类的东西使这个简单的故事复杂化。

循环后面的free应该是正确的(或者至少是'首先释放子数组,然后指向子数组的指针数组'的一般机制 - 所以你需要查看双重自由错误的位置是来自。我们无法看到ip_ptr->funge_height被控制的位置; funge描述ip_ptr->funge_height并不是很明显。


请参阅'unknown @ google'的答案 - 这是一个数组边界问题。

答案 4 :(得分:2)

分配内存时,它应该是i < height作为循环条件。

取消分配内存时,应该迭代到分配时的索引。 ip_ptr->funge_height应与原始height相同,但显然不是这样。

除此之外,它应该有用。

这是另一种方式,涉及更少的mallocs和释放。

分配:

char **foo = malloc (height * sizeof (char **));
foo[0] = malloc (height * width * sizeof (char *));
for (i = 1;  i < height;  ++i) {
    foo[i] = foo[i-1] + width;
}

要解除分配:

free (foo[0]);
free (foo);

答案 5 :(得分:0)

分配(假设高度> 0且宽度> 0)

char **foo, *row;

assert(height > 0 && width > 0);
foo = malloc(height * sizeof *foo);
row = malloc(height * width * sizeof *row);
assert(foo != NULL && row != NULL);

for (i = 0; i < height; ++i, row += width) 
  foo[i] = row;

assert(row == *foo + height * width);

取消分配

assert(foo != NULL);
free(*foo);
free(foo);

答案 6 :(得分:0)

在这种情况下,您始终可以使用valgrind。只需编译您的可执行文件并运行它:

valgrind --leak-check=full ./a.out

Valgrind将找到所有内存验证并指向所涉及的代码行。

在您的情况下,它可能很容易找到索引问题(&lt; vs.&lt; =)。

答案 7 :(得分:0)

如果您的编译器支持它,您可以使用指向可变长度数组的指针,即

size_t width = 10, height = 5;
char *(*foo)[height][width] = malloc(sizeof *foo);

请记住,在访问数组元素之前,您必须对指针进行反洗,例如

(*foo)[1][2] = "foo";

这样做的好处是,您只需分配一个连续的内存块,可以通过free()的单个调用解除分配。

答案 8 :(得分:0)

这100%在没有exe崩溃的情况下工作。

char **map2d;
map2d=(char **)malloc(MAXY*sizeof(char *));
for(int a=0; a<MAXY; a++)
    map2d[a]=(char *)malloc(MAXX*sizeof(char));
for(int a=0; a<MAXX; a++)
    free(map2d[a]);
free(map2d);