在C中实现负责释放值的链表?

时间:2015-12-09 16:30:26

标签: c memory-management linked-list

我正在C中实现一个链表,我遇到的问题是C没有实现任何特定的内存管理方案,只是让你能够通过传递指针来分配和释放内存。没有关于该计划后期是否需要该值的概念。

我在线查找链接列表的典型实现基本上解除了已删除节点的释放,但没有取消分配节点的值。

从列表中删除时,释放由值占用的内存应该是谁的责任?链接列表或程序的正常流程?

示例:

// allocate 10 bytes
char *text = malloc(sizeof(char) * 10);

// create the linked list
LinkedList *list = list_create();

// add the text pointer to the linked list
list_append(list, text);
// remove the pointer from the linked list
list_remove_last(list);

在这种情况下,文本最终不会被释放,因为list_remove_last只释放新节点占用的内存。什么是释放文本占用的内存的正确方法?

4 个答案:

答案 0 :(得分:4)

这是C中容器实现的一种非常常见的方式。 基本上你动态分配列表的内容并将指针传递给容器,现在容器负责释放它。

您还可以将函数指针传递给list_create(),以便它知道如何正确地执行list_remove_last(),这对于使用不知道它将包含哪种类型的元素的通用容器特别有用(它只会持有void *指针)。 想想数据本身是包含其他指针的结构的情况。在这种情况下,list_remove()不能在其数据字段上执行简单的free(),而应该使用传入的函数指针来释放数据。

你的方法有一个小问题:

如果你有list *作为list_create()的返回类型,那么你必须在你的main函数中做一个free(list)。或者,你可以让list_create()返回一个列表,而不是列表*,这是一个逻辑选择,因为列表的大量信息是动态分配的,并且无论如何都可以通过指针访问。

在第二种情况下,您需要一个函数list_destroy(list)来破坏列表中的任何元素。

答案 1 :(得分:3)

我的指导思路是:分配内存的人也负责取消分配。

如果实现为值分配内存的链接列表,则实现还应该在从列表中删除条目时释放此内存。对于字符串,可以通过将字符串复制到新分配的足够大小的缓冲区来完成。

如果链接列表的实现只存储普通值(例如指针)而没有为值分配额外的内存,那么它也应该避免释放它没有分配的内存,因为它不知道分配器为这个内存计划了什么在将来。

答案 2 :(得分:3)

  

C没有实现任何特定的内存管理方案,只是让你能够通过传递指针来分配和释放内存

是的,C缺少任何类型的自动内存管理,因此您必须小心释放您实例化的任何内存块。

  

从列表中删除时,释放由值占用的内存应该是谁的责任?链接列表或程序的正常流程?

这是你的责任。你可以随心所欲地做到这一点。您可以编写通用链接列表,其中调用者必须负责为列表中的每个值分配和释放空间,因为列表管理功能不知道每个值可能需要多少空间,或者是否需要值超出节点的生命周期。或者,您可以编写一个列表实现来管理节点的每个方面,包括存储在节点中的值的空间。在某些情况下,列表节点包含节点定义中的值,如:

struct Node {
    struct Node *next;
    int value;
};

并且其他时候节点具有指向具有实际值的其他块的指针:

struct Node {
    struct Node *next;
    void *value;
};

另一种方法是定义一个只包含列表操作所需部分的结构(即next指针),然后将数据搭载到该结构上:

struct Node {
    struct Node *next;
};

struct MyNode {
    struct Node node;
    int price;
    int quantity;
};

所以,有很多方法可以做到,而且没有一个是错的。您应该选择适合您需求的风格。您是否有大的复杂值,您不想复制,要存储在链表中,但是即使它们从列表中删除后仍要继续使用?选择上面的第一个风格。您想在一个地方管理与链接列表相关的所有内容吗?然后选择第二种风格。

重点是:C比其他语言要少得多,虽然这意味着你必须更加努力地思考程序的正确性,但你也可以自由地以你选择的方式直接做事。拥抱那个。

答案 3 :(得分:2)

正确的方法是让list_remove_node()函数不仅可以释放列表(节点)本身,还可以释放为该特定节点分配的值。此外,您不应该根据文本搜索特定节点,因为您应该只能调用free(node->text)(即使在当前的list_remove_last()函数中也可以这样做)

主要的C逻辑是你应该释放()你自己分配的任何东西。某些图书馆会为自己的工作分配内存,这通常也是你应该清理的(因为你是那个要求它的人)。