在C中释放()malloc的二维数组的最佳方法
假设我有一个用这样的东西创建的二维数组,
char **foo = (char **) malloc(height * sizeof(char *)); for(i = 0; i <= height; i++) foo[i] = (char *) malloc (width * sizeof(char *));
首先,这甚至是创建像这样的数组的正确方法吗? 这里的问题是,’height’和’width’是在运行时设置的东西。
这似乎有效,但这是释放这个2Darrays的最佳策略。 免费(funge)听起来不对。 通过这里的其他post,我想我会逐一释放每一行?
我确实试过这样的事,
for (height = 0; height funge_height; height++) { free(funge[height]); } free(funge)
然而,这给了我一个双重自由指针exception。 这是不是意味着,我不需要管理这段记忆? 我的印象是,对于每个malloc的内存,我们应该调用free()。
由于所有’行’都是相同的大小,你可以一举分配它,使用malloc(height * width * sizeof (char *))
(你是不是要创建一个二维的char
数组或者一个2d数组char *
)。 您可以使用乘法来计算适当的索引(即foo[i][j]
变为foo + i * height + j
),
free()
同样,只需一个电话。
在用于分配的for循环中,您使用i <= height;
而不是i < height;
。 因此,您正在写入无效的内存位置,并且代码的行为变得不可预测。
第二个分配应该是:
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);
分配的机制是可以的(尽管你应该在分配循环中使用sizeof(char)
而不是sizeof(char *)
;在分配宽度和高度是运行时值时,你要分配字符串)。
你应该为每个malloc()调用一次free()的印象基本上是正确的(像calloc()和realloc()之类的东西使这个简单的故事复杂化)。
循环后跟free应该是正确的(或者至少是’首先释放子数组,然后指向子数组的指针数组的一般机制) – 所以你需要检查双重自由错误的来源。 我们看不到ip_ptr->funge_height
控制位置; 由ip_ptr->funge_height
描述ip_ptr->funge_height
并不是很明显。
查看’unknown @ google’的答案 – 这是一个数组边界问题。
分配内存时,它应该是i < height
作为循环条件。
取消分配内存时,应该迭代到分配时的相同索引。 ip_ptr->funge_height
应该与原始height
相同,但显然不是这样。
除此之外,它应该工作。
这是另一种方式,涉及更少的mallocs和frees。
分配:
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);
分配(假设高度> 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);
在这种情况下,您始终可以使用valgrind。 只需编译您的可执行文件并运行它:
valgrind --leak-check=full ./a.out
Valgrind将找到所有内存validation并指向所涉及的代码行。
在您的情况下,它可能很容易找到索引问题(
如果您的编译器支持它,您可以使用指向可变长度数组的指针,即
size_t width = 10, height = 5; char *(*foo)[height][width] = malloc(sizeof *foo);
请记住,在访问数组元素之前,您必须对指针进行derefence,例如
(*foo)[1][2] = "foo";
这样做的好处是,您只需分配一个连续的内存块,可以通过free()
单个调用解除分配。
这100%的工作没有exe崩溃。
char **map2d; map2d=(char **)malloc(MAXY*sizeof(char *)); for(int a=0; a