循环单链表中的内存释放

Memory Deallocation in Circular Singly Linked List

我目前正在更新我对数据结构的了解。今天我决定看一下链表。我已经完成了单链表和双向链表的基本概念。但是我在用C实现循环单链表的时候遇到了一个小问题

在创建了3个节点的循环单链表并打印层次结构后,我想释放节点的内存。但是,每当我尝试 运行 代码时,都会抛出异常。据我了解,问题与 free(one); 行有关。正如您在我的代码中看到的那样,我什至试图预先断开节点之间的链接。这个问题背后的原因是什么,是因为我以错误的方式释放循环链表中的内存吗?如果没有,应该遵循什么方法来摆脱这个问题?

#include <stdio.h>
#include <stdlib.h>

typedef struct NodeSL nodeSL;

struct NodeSL{
    int data;
    nodeSL *next;
};

void circularLinkedList();

int main(){

    /* Circular Link List Example */
    circularLinkedList();

    return 0;
}

void circularLinkedList(){
    /* Initializing the nodes. */
    nodeSL *head,*one,*two,*three;

    /* Allocating the memory. */
    one=(nodeSL*)malloc(sizeof(nodeSL));
    two=(nodeSL*)malloc(sizeof(nodeSL));
    three=(nodeSL*)malloc(sizeof(nodeSL));

    /* Assigning data values. */
    one->data=1;
    two->data=2;
    three->data=3;

    /* Connecting the nodes. */
    one->next=two;
    two->next=three;
    three->next=one;

    /* Saving the address of the first node in head. */
    head=one;

    nodeSL *p;
    int flag=1;
    p=(nodeSL*)malloc(sizeof(nodeSL));
    p=head;
    printf("THIS IS AN EXAMPLE OF A CIRCULAR LINKED LIST!\n");
    printf("Head has the address %u\n",head);
    while (flag) {
        printf("Data: %d",p->data);
        printf("\tAdress: %u",p);
        printf("\tPoints Forward to the Address: %u\n",p->next);  
        p=p->next;
        if(p==one)
        {
            flag=0;
        }
    }
    printf("\n\n");
    /* Deallocating the memory. */
    three->next=NULL;
    two->next=NULL;
    one->next=NULL;
    head=NULL;
    free(p);
    free(two);
    free(three);
    free(one);
}

您将 head 设置为 one。然后你设置 p 等于 head,因此设置 p 等于 one。那你free(p)还要free(one)。所以你释放了一个你已经释放的分配块。

此外,这段代码很神秘:

    p=(nodeSL*)malloc(sizeof(nodeSL));
    p=head;

为什么分配一个新节点然后将 p 更改为指向 head 并泄漏您刚刚毫无意义分配的节点?您希望 p 指向 head 已经指向的节点,还是希望 p 指向 newly-allocated 节点?拿定主意。

这里可能有两个错误。

  1. pheadheadone,释放pone意味着释放指针两次。
    /* Saving the address of the first node in head. */
    head=one;
  1. 分配内存泄漏,立即重新分配。
    p=(nodeSL*)malloc(sizeof(nodeSL));
    p=head; // p is leaked.

我猜你真的想要 p->next = head

您正在陷入一些初学者在使用指针时遇到的经典陷阱。

nodeSL *p;
p = malloc(sizeof(nodeSL));
p = head;

// ...

free(p)

您忘记了指针只是一个引用某些内存位置的数字。如果你想使用指针(在本例中,p)来遍历你的列表,你不需要从系统申请内存。

简而言之,你这里有一个double-free。您释放 p,然后释放 one,这与循环后 p 的值相同。如果您使用调试器,您会在这一行看到错误。

此外,您分配了内存,将其存储在 p 中,并通过在 p 中存储不同的值立即 泄漏了 该内存。

所以,不要这样做,你会没事的。