为什么 free 会这样工作?

Why does free work like this?

给定以下代码:

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 进行了测试,实际上顶部循环正确地释放了所有动态内存,但是如果我删除识别的行,我会泄漏内存。

怎么来的?

data是指向指针的指针。这意味着 data 指向动态分配的指针数组,然后每个指向实际数据。第一个 for 循环释放数组中的每个指针,但您仍然需要将原始指针释放到您已经释放的其他点的数组。这就是您指出的行的原因。

根据一般经验,每个 malloc() 都应该有一个对应的 free() 调用。如果您查看此程序中分配内存的代码,您很可能会看到与您在此处发布的释放内存的代码非常严格的对应关系。

让我们看一下您在程序中使用的内存图:

+---------+       +---------+---------+---------+-----+
| data    |  -->  | char *  | char *  | char *  | ... |
+---------+       +---------+---------+---------+-----+
| count   |            |         |         |
+---------+            v         v         v
                     +---+     +---+     +---+
                     | a |     | b |     | c |
                     +---+     +---+     +---+
                     |...|     |...|     |...|
                     +---+     +---+     +---+

在 C 中,我们可以为 (更简单地说,一个数组)元素动态分配 space。但是,我们不能使用数组类型来引用该动态分配,而是使用指针类型。在这种情况下,指针只是指向动态分配数组的第一个元素。如果你给指针加1,你会得到一个指向动态分配数组第二个元素的指针,加2得到一个指向第二个元素的指针,依此类推。

在 C 中,括号语法 (data[1]) 是 shorthand,用于对指针进行添加和取消引用。所以C中的指针可以这样像数组一样使用

在图中,data 指向动态分配数组中的第一个 char *,它在内存中的其他地方。

data 指向的数组的每个成员都是一个字符串,本身是动态分配的(因为元素是 char *s)。

因此,循环释放字符串('a...''b...''c...' 等),free(tokens->data) 释放 data 指向的数组,最后,free(tokens) 释放整个结构。