假设我有一个二维数组,它是用这样的东西创建的,
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()。
答案 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);