我正在用c写一个基于双链表的代码。我错误地认为通过做free(head_node)
来删除头节点。随着运行的进行,我可以看到电脑变慢了(这显然是由于内存泄漏)。我搜索了stackoverflow和其他网站,我通常遇到的删除链表的代码是:
Node* current = head;
while( current != NULL ) {
Node* next = current->Next;
free( current );
current = next;
}
当我在我的代码中尝试这样做时,程序只是挂在free语句之后,而不返回到调用该语句的函数。上面的代码与双链表相关吗?我的列表成员数据也包含了很多指针。当我对其中一个链接执行free操作时,它是否释放了成员指向的所有数据?请建议和澄清代码片段或参考书籍。谢谢你。
当我对其中一个链接执行free操作时,它是否释放了成员指向的所有数据?
。如果在垃圾收集语言中删除对对象的最后一个引用,就会发生这种情况,但是C语言不是这样工作的。您需要手动释放已分配的每个内存位。
这段代码看起来就像你通常使用的单链表或双链表,假设它的值都不是指针。
我的list成员数据也包含很多指针。
因为它们是你需要释放每个current->value
以及(如果它们是指针指向指针…)
您发布的代码应该适用于单链表或双链表,但做了一些假设:
- 在释放节点之前不需要清理节点;这通常是一个错误的假设。
- 列表的末尾标记为NULL指针(即最后一个节点的
Next
成员是NULL
)
第一个假设:由于您已经在节点中动态分配了数据,并且假定您在其他地方没有指向该数据的另一个指针,您将在稍后使用该指针进行清理,因此您需要在释放每个节点之前释放该数据。在C语言中,这不是为你做的;一般规则是,如果您必须自己分配它,那么您也必须自己释放它。处理这种情况的一个明智的方法是编写一个函数来清理和释放节点,并调用该函数,而不仅仅是调用free()
;您的清理函数仍然会释放节点,但它会首先释放节点的数据。
关于第二个假设:将最后一个节点的Next
指针设置为NULL
来标记结束是一种非常常见的做法,因为这样可以很容易地判断您何时已经遍历了整个列表。对于双重链表,第一个节点的Prev
指针也是如此。但是,如果它是一个循环列表,那么最后一个节点就会指向第一个节点——这将破坏您发布的代码。在这种情况下,您将从节点head->Next
而不是head
开始,并检查current
是否不是head
而不是NULL
。然后在最后处理head
,因为您最初跳过了它。
还有一点:请确保在您完成释放列表后,您不会让head
指向无效(已释放)节点,然后再次尝试访问列表…