在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