双重递归中的 Malloc 和 free
Malloc and free in double recursion
当我遇到以下问题时,我正在玩 C 代码。我有一个看起来像这样的代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct a {
int n1;
int n2;
} el;
typedef struct list {
el *elements;
int nElements;
} list;
void copyList(list in, list *out) {
int i;
for(i = 0; i < in.nElements; i++) {
out->elements = realloc(out->elements,sizeof(el)*(out->nElements + 1));
out->elements[i] = in.elements[i];
out->nElements = out->nElements + 1;
}
}
void initList(list *l) {
l->nElements = 0;
l->elements = NULL;
}
void freeList(list *l) {
l->nElements = 0;
if(l->elements != NULL) {
free(l->elements);
l->elements = NULL;
}
}
void testRecur(int i, list l) {
list l1;
if(i > 0) {
initList(&l1);
copyList(l,&l1);
// freeList(&l);
testRecur(i-1,l1);
testRecur(i-2,l1);
// freeList(&l1);
}
else {
// freeList(&l);
}
}
int main(void) {
list l1;
list l2;
el element;
initList(&l1);
initList(&l2);
l1.elements = malloc(sizeof(el)*2);
l1.nElements = 2;
element.n1 = 1;
element.n2 = 2;
l1.elements[0] = element;
element.n1 = 3;
element.n2 = 4;
l1.elements[1] = element;
testRecur(10,l1);
// freeList(&l1);
return 0;
}
这是一个简单的代码,递归地复制一个列表一定次数。它没有任何意义,但很容易解释这个概念。问题是:我应该把 free
电话放在哪里?我已经尝试了评论点的所有组合,但我最终遇到了双重释放错误 (*** Error in ./a.out: double free or corruption (fasttop): 0x0000000001ecd010 ***
) 或使用 valgrind
进行内存泄漏检测(具有以下参数:valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./a.out
) .有没有办法不泄漏内存(至少根据 valgrind)?
关于:
void testRecur(int i, list l) {
list l1;
if(i > 0) {
initList(&l1);
copyList(l,&l1);
对copyList()
的调用将对realloc()
的调用结果放在局部变量l1
中,但是,那些realloc()
d内存永远不会传递给free()
建议:
void testRecur(int i, list l)
{
list l1;
if( i > 0 )
{
initList(&l1);
copyList(l,&l1);
testRecur(i-1,l);
freeList(&l1);
}
}
然后当递归展开堆栈时,局部变量分配的内存将被释放。
但是,这会导致函数的第二个参数永远不会被释放。所以main()
函数仍然需要free()
那个参数
解决方案是从 testRecur() 函数中删除所有出现的 freeList(&l);。
解释:
使用 alloc(及其变体)和 free 的一个好习惯是尝试在同一范围内同时执行这两项操作。在您的示例中,将内存分配给列表的函数位于 main() 和 copyList().
中
1.main() 函数分配和取消分配可以很容易地在同一个范围内完成:
int main(void) {
/*
Initialization code
*/
// Allocation
l1.elements = malloc(sizeof(el)*2);
l1.nElements = 2;
/*
Process list l1, but dont play with its memory.
A thumb rule can be to pass l1(by reference) as const
*/
// De-allocation
freeList(&l1);
return 0;
}
2.copyList():根据代码,我们不能在copyList[=37=中释放列表] 本身,因为我们稍后需要它。所以我们做下一个最好的事情 - 在调用 copyList 的函数中取消分配。想想 copyList 有两部分 - 分配和复制。
void testRecur(int i, list l) {
list l1;
if(i > 0) {
initList(&l1);
/* memory will be allocated in copyList.
So, allocation scope starts here */
copyList(l, &l1);
/* Process list l1, but again, dont play with its memory */
testRecur(i-1,l1);
testRecur(i-2,l1);
/* Now l1 is no more required, its scope is finished.
We can free l1. */
freeList(&l1);
}
}
注意:这与分配和释放无关,但是将结构(列表)作为值传递在您的示例中没有意义,因此最好在函数 testRecur() 中通过引用传递列表.
当我遇到以下问题时,我正在玩 C 代码。我有一个看起来像这样的代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct a {
int n1;
int n2;
} el;
typedef struct list {
el *elements;
int nElements;
} list;
void copyList(list in, list *out) {
int i;
for(i = 0; i < in.nElements; i++) {
out->elements = realloc(out->elements,sizeof(el)*(out->nElements + 1));
out->elements[i] = in.elements[i];
out->nElements = out->nElements + 1;
}
}
void initList(list *l) {
l->nElements = 0;
l->elements = NULL;
}
void freeList(list *l) {
l->nElements = 0;
if(l->elements != NULL) {
free(l->elements);
l->elements = NULL;
}
}
void testRecur(int i, list l) {
list l1;
if(i > 0) {
initList(&l1);
copyList(l,&l1);
// freeList(&l);
testRecur(i-1,l1);
testRecur(i-2,l1);
// freeList(&l1);
}
else {
// freeList(&l);
}
}
int main(void) {
list l1;
list l2;
el element;
initList(&l1);
initList(&l2);
l1.elements = malloc(sizeof(el)*2);
l1.nElements = 2;
element.n1 = 1;
element.n2 = 2;
l1.elements[0] = element;
element.n1 = 3;
element.n2 = 4;
l1.elements[1] = element;
testRecur(10,l1);
// freeList(&l1);
return 0;
}
这是一个简单的代码,递归地复制一个列表一定次数。它没有任何意义,但很容易解释这个概念。问题是:我应该把 free
电话放在哪里?我已经尝试了评论点的所有组合,但我最终遇到了双重释放错误 (*** Error in ./a.out: double free or corruption (fasttop): 0x0000000001ecd010 ***
) 或使用 valgrind
进行内存泄漏检测(具有以下参数:valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./a.out
) .有没有办法不泄漏内存(至少根据 valgrind)?
关于:
void testRecur(int i, list l) {
list l1;
if(i > 0) {
initList(&l1);
copyList(l,&l1);
对copyList()
的调用将对realloc()
的调用结果放在局部变量l1
中,但是,那些realloc()
d内存永远不会传递给free()
建议:
void testRecur(int i, list l)
{
list l1;
if( i > 0 )
{
initList(&l1);
copyList(l,&l1);
testRecur(i-1,l);
freeList(&l1);
}
}
然后当递归展开堆栈时,局部变量分配的内存将被释放。
但是,这会导致函数的第二个参数永远不会被释放。所以main()
函数仍然需要free()
那个参数
解决方案是从 testRecur() 函数中删除所有出现的 freeList(&l);。
解释:
使用 alloc(及其变体)和 free 的一个好习惯是尝试在同一范围内同时执行这两项操作。在您的示例中,将内存分配给列表的函数位于 main() 和 copyList().
中1.main() 函数分配和取消分配可以很容易地在同一个范围内完成:
int main(void) {
/*
Initialization code
*/
// Allocation
l1.elements = malloc(sizeof(el)*2);
l1.nElements = 2;
/*
Process list l1, but dont play with its memory.
A thumb rule can be to pass l1(by reference) as const
*/
// De-allocation
freeList(&l1);
return 0;
}
2.copyList():根据代码,我们不能在copyList[=37=中释放列表] 本身,因为我们稍后需要它。所以我们做下一个最好的事情 - 在调用 copyList 的函数中取消分配。想想 copyList 有两部分 - 分配和复制。
void testRecur(int i, list l) {
list l1;
if(i > 0) {
initList(&l1);
/* memory will be allocated in copyList.
So, allocation scope starts here */
copyList(l, &l1);
/* Process list l1, but again, dont play with its memory */
testRecur(i-1,l1);
testRecur(i-2,l1);
/* Now l1 is no more required, its scope is finished.
We can free l1. */
freeList(&l1);
}
}
注意:这与分配和释放无关,但是将结构(列表)作为值传递在您的示例中没有意义,因此最好在函数 testRecur() 中通过引用传递列表.