我在大学里参加过C编程考试,该考试中的一个问题是如何释放链表数据结构。
我的方法是释放每个节点的数据,但是没有充分的理由,我没有得到该练习的要点。
这是我未接受的代码:
#include <stdlib.h>
struct node {
int value;
struct node *next;
};
void free_list(struct node *head) {
for (struct node *p = head; p != NULL; p = p->next) {
free(p);
}
}
有人可以解释一下这是怎么回事,以及从内存中释放链接列表的正确方法是什么?
答案 0 :(得分:4)
for
循环的最后一部分是在{em>之后读取p->next
。
您需要缓冲指针:
free(p);
答案 1 :(得分:2)
Sander de Dycker 的评论很棒,
花些时间,您会发现:
p
在执行p->next
之前被释放,因此p->next
读取已经释放的内存。
如果您正在寻找一种使用for loop
释放链接列表的好方法,请尝试以下方法:
#include <stdlib.h>
struct node {
int value;
struct node *next;
};
void free_list(struct node *head) {
struct node *q;
for (struct node *p = head; p != NULL; p = q) {
q = p->next;
free(p);
}
}
此错误记录在C Bible by Dennis Ritchie
中答案 2 :(得分:2)
放松打在头上的指甲。使用描述性名称使其更加明显。您要确保保存要释放的指针,然后之前前进到列表中的下一个节点,例如,在保存的指针上调用free
,例如
void free_list(struct node *head)
{
while (head) {
struct node *victim = head; /* save node to free */
head = head->next; /* advance to next before free */
free (victim); /* free node */
}
}
答案 3 :(得分:-1)
有人可以解释这是怎么回事
在节点上调用free
后,您将无法访问head->next
。您必须先免费head->next
head
。
什么是从内存中释放链表的正确方法?
一个很好的解决方案是递归。递归有助于使代码易于理解,但是除非您意识到危险,否则请在生产代码中避免使用。我经常将其用于原型制作。这是一个例子。
void free_list(struct node *head)
{
if(head) {
// Before freeing the first element, free the rest
free_list(head->next)
// Now it's only one element left to free
free(head);
}
}
它像这样工作。假设我们有一个列表:[e0, e1, e2, ..., en]
。我们要释放所有元素。为此,我们首先释放列表[e1, e2, ..., en]
,然后释放元素e0
。下一步以相同的方式工作。我们要释放[e1, e2, ... en]
,因此我们从调用列表[e2, e3, ..., en]
上的相同算法开始,完成后,我们释放e1
。基本情况是当我们得到一个空列表[]
时,我们什么也不做。
您也可以非递归地执行此操作。它虽然不那么漂亮,但通常效率更高,并且消除了堆栈溢出的风险。这就是我在生产代码中写的方式。
void free_list(struct node *head)
{
struct node *tmp;
while(head) {
tmp = head;
head = head->next;
free(tmp);
}
}