43

假设您有以下初始化多维数组的 ANSI C 代码:

int main()
{
      int i, m = 5, n = 20;
      int **a = malloc(m * sizeof(int *));

      //Initialize the arrays
      for (i = 0; i < m; i++) { 
          a[i]=malloc(n * sizeof(int));
      }

      //...do something with arrays

      //How do I free the **a ?

      return 0;
}

使用后**a,如何正确从内存中释放它?


[更新](解决方案)

感谢蒂姆(和其他人)的回答,我现在可以执行这样的功能来从我的多维数组中释放内存:

void freeArray(int **a, int m) {
    int i;
    for (i = 0; i < m; ++i) {
        free(a[i]);
    }
    free(a);
}
4

5 回答 5

74

好的,有相当多的混乱解释了必要的调用必须按什么顺序free(),所以我将尝试澄清人们试图了解的内容以及原因。

从基础开始,要释放使用 分配的内存malloc(),您只需free()准确地调用由 给定的指针malloc()。所以对于这段代码:

int **a = malloc(m * sizeof(int *));

你需要一个匹配:

free(a);

对于这一行:

a[i]=malloc(n * sizeof(int));

你需要一个匹配:

free(a[i]);

在类似的循环内。

这变得复杂的地方是这需要发生的顺序。如果您多次调用以获得几个不同的内存块,通常在您完成它们后malloc()调用什么顺序并不重要。free()但是,这里的顺序很重要,原因非常具体:您正在使用一块malloced 内存来保存指向其他malloced 内存块的指针。因为一旦你用 将它交还给它,你 不能尝试读取或写入内存 free(),这意味着你必须在释放块本身a[i] 之前释放块及其存储的指针。a存储有指针的各个块a[i]不相互依赖,因此可以freed 按你喜欢的顺序。

所以,把这一切放在一起,我们得到这个:

for (i = 0; i < m; i++) { 
  free(a[i]);
}
free(a);

最后一个提示:调用时malloc(),请考虑更改这些:

int **a = malloc(m * sizeof(int *));

a[i]=malloc(n * sizeof(int));

到:

int **a = malloc(m * sizeof(*a));

a[i]=malloc(n * sizeof(*(a[i])));

这是在做什么?编译器知道那a是一个int **,所以它可以确定那sizeof(*a)是一样的sizeof(int *)。但是,如果稍后您改变主意并想要chars 或shorts 或longs 或数组中的任何内容而不是ints,或者您修改此代码以供以后在其他内容中使用,您将只需要int更改上面引用的第一行,其他所有内容都会自动为您准备就绪。这消除了将来出现未注意到错误的可能性。

祝你好运!

于 2009-11-14T10:59:45.827 回答
8

完全撤消您分配的内容:

  for (i = 0; i < m; i++) { 
      free(a[i]);
  }
  free(a);

请注意,您必须按照最初分配内存的相反顺序执行此操作。如果您free(a)先这样做,那么a[i]将在释放内存后访问内存,这是未定义的行为。

于 2009-11-14T10:16:51.573 回答
4

您需要再次迭代数组并为指向的内存执行与 malloc 一样多的释放,然后释放指针数组。

for (i = 0; i < m; i++) { 
      free (a[i]);
}
free (a);
于 2009-11-14T10:16:27.890 回答
3

以完全相反的顺序编写分配运算符,更改函数名称,你会没事的。

  //Free the arrays
  for (i = m-1; i >= 0; i--) { 
      free(a[i]);
  }

  free(a);

当然,您不必完全相同的相反顺序解除分配。您只需要准确地跟踪一次释放相同的内存,而不是“忘记”指向已分配内存的指针(就像您释放第一个内存一样a)。但是以相反的顺序解除分配是解决后者的一个很好的拇指角色。

正如litb在评论中指出的那样,如果分配/解除分配有副作用(如C++ 中的new/delete运算符),有时解除分配的向后顺序会比这个特定示例更重要。

于 2009-11-14T10:18:50.247 回答
1

我只会调用 malloc() 和 free() 一次:

#include <stdlib.h>
#include <stdio.h> 

int main(void){
  int i, m = 5, n = 20;
  int **a = malloc( m*(sizeof(int*) + n*sizeof(int)) );

  //Initialize the arrays
  for( a[0]=(int*)a+m, i=1; i<m; i++ ) a[i]=a[i-1]+n;

  //...do something with arrays

  //How do I free the **a ?
  free(a);

  return 0;
}
于 2009-11-14T10:40:08.233 回答