我创建了这个破坏链表的函数,head
是链表的头部。
void destroy(node** head){
node* current = NULL;
while(*head != NULL){
current = *head;
free(current);
*head = (*head)->next;
}
}
我认为此代码不起作用,因为head
和current
指向内存中的相同地址,并且由于它已被释放,因此您无法访问(*head)->next
。但是当我运行该程序时它运行正常,当我检查列表是空的。
我甚至在程序上运行了valgrind测试,没有内存泄漏,尽管几乎没有神秘错误。
为什么这段代码有效?它似乎不直观。
答案 0 :(得分:3)
我认为此代码无法正常工作,因为
*head
和current
指向内存中的相同地址,并且由于它已被释放,因此无法访问{{1 }}
这完全正确:一旦(*head)->next
free(current)
访问未定义的行为。
不幸的是,未定义的行为并不等同于崩溃,因此人们可能会觉得程序正在运行;它不是!
我甚至在程序上运行了valgrind测试,没有内存泄漏,尽管几乎没有神秘错误。
这不是内存泄漏,而是访问释放的内存。它确实会产生一些含糊不清的错误信息 - 这些内容如下:
地址
块内的4个字节(*head)->next
是16个空闲' d
这意味着0x5a02048
为16,sizeof(node)
的偏移为4。
显然,释放列表的正确方法是交换访问next
的行并调用next
。
free(current)
请注意,while(*head != NULL){
node* current = *head;
*head = (*head)->next;
free(current);
}
可以在循环内声明。
答案 1 :(得分:1)
代码具有未定义的行为,因为您访问的内存只有free
' d。
未定义行为的真正坏处在于,即使代码具有未定义的行为,可能会出现。
将代码更改为:
void destroy(node** head){
node* current = NULL;
while(*head != NULL){
current = *head;
*head = (*head)->next;
free(current);
}
}
以便在致电*head
free
答案 2 :(得分:0)
这很有效,因为在这种特殊情况下,释放的内存没有被修改,即使它是免费的,你也不再拥有它。
不要这样做。在另一个编译器或平台上,它可能会被修改,或者可能会发生非法的内存访问错误,或者你可能会更改程序另一部分使用的内存。这使得这是一个糟糕的方法。只使用程序拥有的内存,
答案 3 :(得分:0)
这是我的解决方案:
void destroy(node** head){
node* current = *head;
while((*head) != NULL){
if((*head)->next!=NULL)
*head = (*head)->next;
else { /* if next node is NULL, free it and comes out of loop or function **/
(*head) = NULL;
free(current);
current = NULL;/* to avoid Dangling pointer problem **/
break;//or return bcz there will not be further node to delete **/
}
/** below 2 statements will execute only if part is true **/
free(current);
current = *head;
}
}