我正在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只释放新节点占用的内存。什么是释放文本占用的内存的正确方法?
答案 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逻辑是你应该释放()你自己分配的任何东西。某些图书馆会为自己的工作分配内存,这通常也是你应该清理的(因为你是那个要求它的人)。