【问题标题】:C: How to free nodes in the linked list?C:如何释放链表中的节点?
【发布时间】: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 时会出现分段错误。

标签: c linked-list heap-memory


【解决方案1】:

释放列表的迭代函数:

void freeList(struct node* head)
{
   struct node* tmp;

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

}

函数的作用如下:

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

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

  3. 现在我们可以安全地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?
        猜你喜欢
        • 2018-06-03
        • 1970-01-01
        • 2013-07-23
        • 1970-01-01
        • 1970-01-01
        • 2017-04-02
        • 1970-01-01
        • 2020-10-30
        • 2019-08-18
        相关资源
        最近更新 更多