销毁链表,为什么会这样?

Destroying linked list, why is this working?

我创建了这个销毁链表的函数,head是链表的头部。

void destroy(node** head){

    node* current = NULL;
    while(*head != NULL){
        current = *head;
        free(current);
        *head = (*head)->next;
    }

}

我认为这段代码不会起作用,因为 headcurrent 指向内存中的相同地址,并且由于它已被释放,您无法访问 (*head)->next .但是当我 运行 程序运行良好时,当我检查列表时它是空的。

我什至 运行 对该程序进行了 valgrind 测试,没有内存泄漏,尽管有一些神秘的错误。

为什么这段代码有效?好像不太直观。

之所以有效,是因为在这种特殊情况下,释放的内存没有被修改,即使它是免费的并且您不再拥有它。

不要这样做。在另一个编译器或平台上,它可能会被修改,或者可能会发生非法内存访问错误,或者您可能会更改程序另一部分使用的内存。这使它成为一种糟糕的方法。仅使用您的程序拥有的内存,

I thought that this code won't work because *head and current point to the same address in memory, and since it was freed, you can't access (*head)->next

完全正确:一旦您 free(current) 访问 (*head)->next未定义的行为

不幸的是,未定义的行为不等同于崩溃,因此可能给人一种程序正在运行的印象;它不是!

I even ran a valgrind test on the program, there was no memory leaks, although there is few cryptic errors.

这不是内存泄漏,而是对已释放内存的访问。它确实会导致有点神秘的错误消息 - 大致如下:

Address 0x5a02048 is 4 bytes inside a block of size 16 free'd

这个意思就是sizeof(node)是16,next的偏移量是4。

显然,释放列表的正确方法是交换访问 next 的行并调用 free(current).

while(*head != NULL){
    node* current = *head;
    *head = (*head)->next;
    free(current);
}

注意 current 可以在循环内声明。

代码有 未定义的行为 当您访问您刚刚 free 的内存时。

未定义行为的真正坏处是它可能看起来工作,即使代码有未定义的行为。

将代码更改为:

void destroy(node** head){   
    node* current = NULL;
    while(*head != NULL){
        current = *head;
        *head = (*head)->next;
        free(current);
    }
}

以便您在调用 free

之前更改 *head

这是我的解决方案:

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;
                }
        }