C:如何释放链表中的节点?

Posted

技术标签:

【中文标题】C:如何释放链表中的节点?【英文标题】:C: How to free nodes in the linked list? 【发布时间】:2011-09-19 00:25:14 【问题描述】:

如何释放在另一个函数中分配的节点?

struct node 
    int data;
    struct node* next;
;

struct node* buildList()

    struct node* head = NULL;
    struct node* second = NULL;
    struct node* third = NULL;

    head = malloc(sizeof(struct node));
    second = malloc(sizeof(struct node));
    third = malloc(sizeof(struct node));

    head->data = 1;
    head->next = second;

    second->data = 2;
    second->next = third;

    third->data = 3;
    third->next = NULL;

    return head;
  

我在main()中调用buildList函数

int main()

    struct node* h = buildList();
    printf("The second element is %d\n", h->next->data);
    return 0;
  

我想释放头部、第二个和第三个变量。 谢谢。

更新:

int main()

    struct node* h = buildList();
    printf("The element is %d\n", h->next->data);  //prints 2
    //free(h->next->next);
    //free(h->next);
    free(h);

   // struct node* h1 = buildList();
    printf("The element is %d\n", h->next->data);  //print 2 ?? why?
    return 0;

两个打印 2. 不应该调用 free(h) 删除 h。如果是这样,为什么 h->next->data 可用,如果 h 是免费的。当然,“第二个”节点没有被释放。但是由于 head 被移除,它应该能够引用下一个元素。这里有什么错误?

【问题讨论】:

您是否在取消链接或释放它们时遇到问题?如果是后者,则使用来自malloc() 的返回值调用free() user349433:这不是硬件,我尝试在 main 中使用 free(h)。那么如果 h 不存在,那么 h->next->data 怎么会给出值 2?于是我问。但是 free(h->next) 也应该被调用。但是既然h是头,去掉头后,我肯定不能引用头->下一个,不是吗。我哪里弄错了? free() 不会擦除内存中的内容,它只是允许这些内容以后再使用。巧合的是,指针 h->next 仍然有效,因为您 free()'d 的内存尚未被重用。 @jase21 Well Heath 回答了这个问题。它只是在您尝试时有效,但不能保证它在将来或在另一台机器上也能正常工作。在另一台机器上做h->next->data 可能会给你带来分段错误。好的,假设您有h 具有以下数据:h->next = 0x12341281; h->data = 1,当您执行free(h) 时,您只需让机器知道将来malloc 您可以覆盖hh 不是更多地被您的程序使用。但是h->next = 0x12341281; h->data = 1 的数据似乎一直存在,这并不意味着您应该使用它们。 @jase21 也许在将来malloc,其中h->nexth->data 被保存,将写入其他内容。然后在执行h->next->data 时会出现分段错误。 【参考方案1】:

释放列表的迭代函数:

void freeList(struct node* head)

   struct node* tmp;

   while (head != NULL)
    
       tmp = head;
       head = head->next;
       free(tmp);
    


函数的作用如下:

    检查head是否为NULL,如果是则列表为空,我们就返回

    head 保存在tmp 变量中,并使head 指向列表中的下一个节点(这在head = head->next 中完成

    现在我们可以安全地free(tmp) 变量,而head 只是指向列表的其余部分,返回步骤1

【讨论】:

只需确保在将列表头指针传递给此函数后将其设置为空即可。事实上,在释放节点之前将每个节点的每个 next 指针设置为 null 也是一个好主意。 @foobar 如果节点中的数据也是使用 malloc 创建的,我们是否必须在释放 temp 之前释放它?喜欢:免费(tmp->数据);免费(tmp); @Robert 是的!如果你先释放tmp,那么 tmp->data 可能会指向垃圾,你会得到一个段错误。 也许最好在 FreeList 函数中直接通过引用传递头指针并将指针设为 NULL。所以,这将是 void freeList(struct node** head)blah;废话; *头=空;。这样可以避免 David 提到的问题。 你们都忽略了非 NULL 头指针根本不会中断循环。【参考方案2】:

只需遍历列表即可:

struct node *n = head;
while(n)
   struct node *n1 = n;
   n = n->next;
   free(n1);

【讨论】:

【参考方案3】:

一个函数就可以完成这项工作,

void free_list(node *pHead)

    node *pNode = pHead, *pNext;

    while (NULL != pNode)
    
        pNext = pNode->next;
        free(pNode);
        pNode = pNext;
    


【讨论】:

【参考方案4】:
struct node
    int position;
    char name[30];
    struct node * next;
;

void free_list(node * list)
    node* next_node;

    printf("\n\n Freeing List: \n");
    while(list != NULL)
    
        next_node = list->next;
        printf("clear mem for: %s",list->name);
        free(list);
        list = next_node;
        printf("->");
    

【讨论】:

【参考方案5】:

你总是可以像这样递归地做:

void freeList(struct node* currentNode)

    if(currentNode->next) freeList(currentNode->next);
    free(currentNode);

【讨论】:

argg,递归在纸面上很不错……但实际上,与像我或 jase21 这样的简单循环相比,它的内存和 CPU 需求非常昂贵。当您有 1328786 个节点时,展开堆栈并不便宜。 @elcuco 我同意。在问题提出的这种情况下,它会表现良好,但如果您正在查看那么大的列表,那么毫无疑问循环会让您处于更好的位置。 这在可以进行尾递归的语言中是可以的。那不是C 这段代码不是尾递归的。 (它在递归之后做某事)并且不能从尾递归优化中受益 我认为如果在 NULL 节点上调用此函数会导致错误。也许在定义的第一行放置一个 NULL 检查,而不是检查下一个节点是否为 null?

以上是关于C:如何释放链表中的节点?的主要内容,如果未能解决你的问题,请参考以下文章

如何删除链表中的头节点? C

如何从c中的双向链表中删除节点

删除单向链表中的某个节点

如何将数据动态存储在C中的链表中?

C语言链表中的节点

检查链表中的每个节点是不是存在 c 中的条件