给出以下代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
为什么我需要额外的:
free(tokens->data);
Run Code Online (Sandbox Code Playgroud)
不应该在for循环中处理吗?
我已经对valgrind/drmemory进行了测试,实际上顶部循环正确地释放了所有动态内存,但是如果我删除了识别的行,我会泄漏内存.
怎么会?
让我们看一下你在程序中使用的内存图:
+---------+ +---------+---------+---------+-----+
| data | --> | char * | char * | char * | ... |
+---------+ +---------+---------+---------+-----+
| count | | | |
+---------+ v v v
+---+ +---+ +---+
| a | | b | | c |
+---+ +---+ +---+
|...| |...| |...|
+---+ +---+ +---+
Run Code Online (Sandbox Code Playgroud)
在C中,我们可以为一组(更简单地说,一个数组)元素动态分配空间.但是,我们不能使用数组类型来引用该动态分配,而是使用指针类型.在这种情况下,指针只指向动态分配的数组的第一个元素.如果向指针添加1,您将获得指向动态分配数组的第二个元素的指针,添加两个指针以获取指向第二个元素的指针,依此类推.
在C中,括号语法(data[1])是添加和解除引用指针的简写.因此,C中的指针可以像数组一样使用.
在图中,data指向char *动态分配的数组中的第一个,这是在内存中的其他位置.
指向的数组的每个成员data都是一个字符串,它本身是动态分配的(因为元素是char *s).
所以,环路将释放字符串('a...','b...','c...',等等),free(tokens->data)重新分配阵列data点,最后,free(tokens)释放整个struct.