给出以下代码:
typedef struct Tokens {
char **data;
size_t count;
} Tokens;
void freeTokens(Tokens *tokens) {
int d;
for(d = 0;d < tokens->count;d++)
free(tokens->data[d]);
free(tokens->data);
free(tokens);
tokens = NULL;
}
为什么我需要额外的费用:
free(tokens->data);
不应该在for循环中处理吗?
我已经对valgrind / drmemory进行了测试,并且顶部循环确实正确地释放了所有动态内存,但是如果我删除了已识别的行,则会泄漏内存。
Howcome?
答案 0 :(得分:6)
让我们看一下您在该计划中使用的记忆图:
+---------+ +---------+---------+---------+-----+
| data | --> | char * | char * | char * | ... |
+---------+ +---------+---------+---------+-----+
| count | | | |
+---------+ v v v
+---+ +---+ +---+
| a | | b | | c |
+---+ +---+ +---+
|...| |...| |...|
+---+ +---+ +---+
在C中,我们可以为组(更简单地说,一个数组)元素动态分配空间。但是,我们不能使用数组类型来引用该动态分配,而是使用指针类型。在这种情况下,指针只指向动态分配的数组的第一个元素。如果向指针添加1,则会获得指向动态分配数组的第二个元素的指针,添加两个指针以获取指向第二个元素的指针,依此类推。
在C中,括号语法(data[1]
)是添加和解除引用指针的简写。因此,C中的指针可以像数组一样使用。
在图中,data
指向动态分配的数组中的第一个char *
,该数组位于内存的其他位置。
data
指向的数组的每个成员都是一个字符串,它本身是动态分配的(因为元素是char *
s)。
因此,循环取消分配字符串('a...'
,'b...'
,'c...'
等),free(tokens->data)
释放数组data
指向,最后,free(tokens)
释放整个结构。
答案 1 :(得分:4)
data
是指向指针的指针。这意味着data
指向动态分配的指针数组,然后每个指针都指向实际数据。第一个for循环释放数组中的每个指针,但是你仍然需要将原始指针释放到已经释放的其他点的数组中。这就是你指出的那条线的原因。
答案 2 :(得分:3)
作为一般经验法则,每个malloc()
都应该对free()
进行相应的调用。如果你看看在这个程序中分配内存的代码,你很可能会看到与你在这里发布的代码非常严格的对应,从而释放内存。