free() 函数只释放结构的第一个元素?

free() function only frees the first element of a struct?

我正在使用两个结构:

typedef struct ListNode{
    void* value;
    struct ListNode *next;
    struct ListNode *prev;
} Node;

typedef struct List{
    Node *first;
    Node *last;
    int count;
} List;

然后我声明这些变量并分配内存

List *x = calloc(1,sizeof(List));
Node *x1 = malloc(sizeof(Node));
Node *x2 = malloc(sizeof(Node));
x->first = x1;
x->last =x2;
x->count = 2;
free(x);

所以我很确定如果我释放 xx->countx->firstx->last 也会消失。然而,在这种情况下,我使用 gdb 进行检查,令人惊讶的是只有 x 的第一个元素被删除(例如:如果在结构 List 中我将计数放在顶部,那么它只会删除计数并留下完好无损)。为什么会这样,我如何 free() 整个结构?

你的假设是错误的。如果你这样做 free(x) 你只是释放了保存 x 内容的内存块,但是由于 这个块包含一些指向其他块的指针 ,你将首先需要 free() 那些。这是因为 free() 不关心你正在释放的内存的内容,它不会做任何花哨的事情。如果在使用 free() 后看到某些值被修改,那只是因为 free() 使用该内存存储一些有用的内部值以跟踪内存使用情况,如果 [=30] 发生这种情况只是巧合=] 结构中的指针。

free() 结构的正确方法如下:

free(x->first);
free(x->last);
// DO NOT free(x->count), it's an integer, not a previously allocated pointer!
free(x);

这是一个可视化表示(请原谅我糟糕的笔迹):

了解结构的内存布局很重要...我不是专家所以这将非常简化:

列表 x = [pointer-to-x1][pointer-to-x2][int](加上填充)

因此,当您 运行 calloc(1, sizeof(List)) 时,您并不是在与 List 相同的内存区域中创建 x1 和 x2 结构,因为它们只是指向某些记忆中的其他地方。您只是在创建对它们的小参考,甚至还没有设置。这就是为什么你必须分别 malloc x1 和 x2。

因此,当您释放 (x) 时,您也不会释放 x1 或 x2。 free 不知道如何,也不知道您 运行 x1 和 x2 的 malloc。如果它试图释放它,它可能会过早释放内存或释放堆栈上的内存。它只会查看我上面映射的内存区域。

正在写这篇文章,看到另一个答案刚刚进来。Marco 的答案很好!

您似乎对调用 free 时会发生什么抱有无效的期望。 您无法在 GDB 中验证 free 的结果。

释放内存位置并不意味着该位置的内存以任何方式被修改。它可能看起来仍然和以前一样。 OS 或 C 运行时库可能会将其设置为全零,但这不是强制性的。指针x也不会改变。

释放一个地址只意味着你告诉 OS 它可以收回它并给别人。 调用 free 后,您将不再被允许访问内存。 这就是 free 之后发生的所有事情。

因此lastcount不会"disappear"。

就是说,正如其他人已经指出的那样,您也存在内存泄漏。释放 x 不会释放任何其他可通过 x->firstx->last.

访问的内存