C:正确释放多维数组的内存
Posted
技术标签:
【中文标题】C:正确释放多维数组的内存【英文标题】:C: Correctly freeing memory of a multi-dimensional array 【发布时间】:2010-12-16 13:46:41 【问题描述】:假设您有以下初始化多维数组的 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);
【问题讨论】:
术语狡辩:这不是 C 通常所说的“多维数组”。这只是使用语法a[i][j]
的唯一方法,同时仍然允许在编译时两个维度都是未知的。另一种多维数组是数组的数组,而不是指向数组(的第一个元素)的指针数组。
【参考方案1】:
好的,有相当多的混乱解释到底是什么顺序
必要的free()
电话必须在,所以我会尝试澄清什么
人们正在尝试了解以及为什么。
从基础开始,释放已分配的内存
使用malloc()
,您只需使用指针调用free()
malloc()
给你的。所以对于这段代码:
int **a = malloc(m * sizeof(int *));
你需要一个匹配的:
free(a);
对于这一行:
a[i]=malloc(n * sizeof(int));
你需要一个匹配的:
free(a[i]);
在一个类似的循环中。
这变得复杂的地方在于它需要发生的顺序。如果
您多次致电malloc()
以获得几个不同的块
记忆,一般来说,你打电话给free()
的顺序并不重要
你已经完成了他们。但是,顺序在这里很重要
具体原因:你正在使用一大块malloc
ed 内存来保存
指向malloc
ed 内存的其他块的指针。因为你必须
不要在你交还内存后尝试读取或写入内存
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])));
这是做什么的?编译器知道a
是一个int **
,所以它可以
确定sizeof(*a)
与sizeof(int *)
相同。然而,如果
稍后你改变主意并想要char
s 或short
s 或long
s 或
数组中的任何内容而不是int
s,或者您修改此代码以供以后使用
用在别的东西上,你只需要改变剩下的
在上面引用的第一行中引用int
,以及其他所有内容
会自动为您到位。这消除了可能性
未来未被注意到的错误。
祝你好运!
【讨论】:
+1 很好的答案;感谢您解释关于“逆序”的问题以及关于做sizeof(*a)
的要点
另外,如果我错了,请纠正我,但我是否正确地说sizeof(*a[i])
等同于您的sizeof(*(a[i]))
,因为数组符号[]
的优先级高于@ 987654356@?
不,我认为你是对的。 en.wikipedia.org/wiki/… 但是,我根据经验法则工作,如果我必须查找它,可能其他阅读我的代码的人也必须查找它,所以为了节省他们(以及我,稍后)的麻烦,明确地使用括号有助于澄清事情并节省时间。不过,这只是个人喜好。【参考方案2】:
完全撤消您分配的内容:
for (i = 0; i < m; i++)
free(a[i]);
free(a);
请注意,您必须按照您最初分配内存的相反顺序执行此操作。如果您先执行free(a)
,那么a[i]
将在内存被释放后访问内存,这是未定义的行为。
【讨论】:
说你必须以相反的顺序释放可能会产生误导。你只需要在指针本身之后释放指针数组。 这不是反过来的另一种说法吗? 我认为@Andomar 的意思是你释放 a[i] 的顺序无关紧要,只是你必须在释放 a 之前释放所有它们。换句话说,您可以释放 a[0] 到 a[m-1] 或 a[m-1] 到 a[0] 或所有偶数 a[] 后跟赔率。但我也确定@GregH 并不是意味着您必须以相反的顺序执行 a[],尤其是考虑到他的代码。【参考方案3】:您需要再次迭代数组并为指向的内存执行与 malloc 一样多的释放,然后释放指针数组。
for (i = 0; i < m; i++)
free (a[i]);
free (a);
【讨论】:
【参考方案4】:以完全相反的顺序编写分配运算符,更改函数名称,一切都会好起来的。
//Free the arrays
for (i = m-1; i >= 0; i--)
free(a[i]);
free(a);
当然,您不必必须以完全相同的相反顺序解除分配。您只需要准确地跟踪一次释放相同的内存,而不是“忘记”指向已分配内存的指针(就像您首先释放 a
一样)。但是以相反的顺序解除分配对于解决后者来说是一个很好的经验。
正如 cmets 中的 litb 所指出的,如果分配/解除分配有副作用(如 C++ 中的new
/delete
运算符),有时解除分配的向后顺序会比这个特定示例中更重要.
【讨论】:
为什么一定要在循环中颠倒顺序? 因为a[1]是在a[0]之后分配的,所以你应该先deallocate a[1]。 为什么需要在 a[0] 之前释放 a[1] ?它们是不同的 malloced 块,它们之间没有依赖关系 由于free
在 C 语言中没有副作用(关于您自己的程序代码),因此这似乎并不重要。 “逆向操作”规则对于具有附加到 free
和 alloc
的副作用的语言更为重要,例如带有析构函数/构造函数的 C++。
我很确定大多数人会向前而不是向后释放数组。【参考方案5】:
我只会调用 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;
【讨论】:
如何回答这个问题? Pavel Shved 写出了正确答案。我只是用一些代码写了一个评论。 您应该将 cmets 写入问题的“评论”字段。它还支持代码块。 @litb:请将我的答案复制到问题的评论字段中。谢谢。 没有理由投反对票。我发现许多关于 SO 的问题的答案是“你不应该那样做,而是这样做”。有回答问题的字母和回答问题含义的空间。以上是关于C:正确释放多维数组的内存的主要内容,如果未能解决你的问题,请参考以下文章