C:正确释放多维数组的内存

时间:2009-11-14 10:15:31

标签: c memory-management memory-leaks free malloc

假设您有以下用于初始化多维数组的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后,如何正确地从内存中释放它?


[更新] (解决方案)

感谢Tim(和其他人)answer,我现在可以做这样的功能来释放我的多维数组中的内存:

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

5 个答案:

答案 0 :(得分:65)

好吧,有很多混乱解释究竟是什么顺序 必须进行必要的free()调用,因此我将尝试澄清什么 人们正试图了解和原因。

从基础知识开始,释放已分配的内存 使用malloc(),您只需使用指针调用free()即可 由malloc()给出的。所以对于这段代码:

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

你需要匹配:

free(a);

并为此行:

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

你需要匹配:

free(a[i]);

在类似的循环中。

这变得复杂的是这需要发生的顺序。如果 你多次打malloc()来获得几个不同的块 记忆,一般来说,当你调用free()的顺序并不重要 你已经完成了他们。但是,订单在这里非常重要 具体原因:您正在使用一块malloc个内存来保存 指向malloc内存的其他块的指针。因为必须 一旦您将内存交回,会尝试读取或写入内存 free(),这意味着你将不得不释放这些块 他们的指针存储在a[i] 之前你释放a块本身。 存储在a[i]中的指针的各个块不依赖于每个块 其他,所以可以free d,无论你喜欢哪种顺序。

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

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])));

这是做什么的?编译器知道aint **,所以它可以 确定sizeof(*a)sizeof(int *)相同。但是,如果 稍后你会改变主意,想要charshortlong或 您的数组中的任何内容,而不是int,或者您稍后调整此代码 使用其他东西,你将不得不改变剩下的 在上面第一行引用中引用int,以及其他所有内容 会自动落到你的位置。这消除了可能性 未来的未被注意的错误。

祝你好运!

答案 1 :(得分:8)

完全撤消您分配的内容:

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

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

答案 2 :(得分:4)

你需要再次迭代数组,并为指向内存的malloc执行尽可能多的释放,然后释放指针数组。

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

答案 3 :(得分:3)

以完全相反的顺序编写您的分配运算符,更改函数名称,您就可以了。

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

  free(a);

当然,您不必以相同的反转顺序解除分配。你只需要跟踪一次释放相同的内存,而不是“忘记”分配内存的指针(就像你首先释放a一样)。但是以相反的顺序解除分配是拇指很好地解决后者的问题。

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

答案 4 :(得分: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;
}