【问题标题】:How to delete node from linked list after I print the contents?打印内容后如何从链表中删除节点?
【发布时间】:2011-10-31 22:10:57
【问题描述】:

我在 c 中有一个程序,它接收来自不同客户端和服务器的消息。当消息进来时,它会将消息添加到该列表中。将消息添加到列表后,我将其打印在屏幕和其他服务器上。但是我想在打印后删除包含该消息的节点,因此当调用打印函数时仅打印新消息。打印后如何删除节点?

这是我的结构:

typedef struct trade_list {
    char* trader_msg;
    u_int32_t id_of_sender;
    int sender_timer;
    int local_time;

    struct trade_list *next;
}trade_list;

trade_list *head = NULL;

这是我的打印方式:

  void print_trades()
    {

        trade_list * newnode = head;
        trade_list *previous = NULL;

            while (newnode) {

             previous = newnode;

              if ((elapsed - newnode->local_time >= 8)) 

             printf ("%s\n", newnode->trader_msg);
             newnode = newnode->next;

                if (previous == NULL)
                    head = newnode->next;
                else
                    {
                    previous->next = newnode->next;

                    free(newnode);
                    }
                }
}

因此给了我一个分段错误。我尝试将 newnode->next 更改为 else 部分中的 newnode。 previous->next = new node; 它没有给我一个错误,但它没有擦除节点,因为每次调用打印函数时它都会打印该节点

【问题讨论】:

    标签: c linked-list nodes


    【解决方案1】:

    在你的函数开始时:

    trade_list *prev = NULL;
    

    在循环的每次迭代中,在 newnode = newnode->next; 之前添加 prev = newnode

    然后删除:

    if (prev == NULL) /* replace the head */
       head = newnode->next;
    else
       prev->next = newnode->next;
    
    /* free newnode? */
    

    相当简单。

    编辑:您确实应该将list_createlist_addlist_remove 之类的函数与您的数据结构相关联,而不是像删除代码一样将其放入打印函数中。这是我创建任何类型的数据结构时要做的第一件事。

    另一种选择是让您的链接列表如下:

    typedef struct trade_node {
       char* trader_msg;
       u_int32_t id_of_sender;
       int sender_timer;
       int local_time;
    
       struct trade_node *next;
    } trade_node;
    
    typedef struct trade_list {
       trade_node *head;
       /* trade_node *foot; ? */
       size_t length;
    } trade_list;
    

    EDIT2:至于您的编辑,将print_trades 更改为:

    void print_trades()
    {
       trade_list *prev = NULL, *next;
       trade_list *newnode = head;
    
       while (newnode) {
    
          if ((elapsed - newnode->local_time >= 8)) {    
             printf ("%s\n", newnode->trader_msg);
    
             /* temp variable for newnode->next */
             next = newnode->next;
    
             if (prev == NULL) /* replace the head */
                head = next;
             else
                prev->next = next;
    
             /* free newnode->trader_msg? */
             free(newnode);
    
             /* don't update prev */
             newnode = next;
          }
          else {
             prev = newnode;
             newnode = newnode->next;
          }
    
       }
    }
    

    在您的代码中,previous 永远不会是NULL,因为您在循环开始时将其设置为newnode,并且newnode 也不应该等于newnode->next,直到newnode 之后完全处理。在 freed 之后,你也在使用 newnode

    【讨论】:

    • 是的,我确实有添加和排序的功能。我只是不认为我需要打印,因为我认为我很简单,可以在打印功能中完成。您上面建议的代码正是我之前使用的代码,但是对于 prev->next = newnode->next 部分 @AusCBloke 不断出现分段错误
    • @AdamAdamou 是否检查了 prev == NULL 以了解头部被移除的情况?如果你不这样做,你会从prev->next 得到一个段错误,因为prevNULL
    • 是的,我做了那个检查。让我编辑上面的代码,这样你就可以确切地看到我做了什么。
    • @AdamAdamou 我根据您的编辑添加了更多代码。告诉我它是否有任何问题,因为我做得很快。
    • @AdamAdamou 如果您在看到此评论之前尝试了我刚刚发布的代码,请再试一次。我编辑了一个小错误。
    【解决方案2】:

    不要让print_trades 依赖于全局变量head,而是让它接收这个“头”作为参数并从那里打印。这在设计方面要好得多。

     void print_trades(trade_list* head){ ... }
    

    然后,如果您将新节点添加到列表的末尾,您可以从第一个新节点开始打印它。如果您不使用此信息而不是打印它们,则无需将它们存储在全局列表中。只需在接收它们的函数中使用本地列表,然后打印该列表。

    删除列表通常通过在每个指针上调用free(ptr) 来完成。由于您知道如何将节点添加到列表中,因此您将知道如何适当地反转它。

    【讨论】:

      【解决方案3】:

      花一些时间查看链表处理和从链表中删除项目...一旦您的“打印”执行,只需执行删除...

      基本上你希望有一些trade_list指针对象指向要删除的节点和前一个节点。让前一个节点的“next”指向要删除的节点的next,然后释放已删除节点上的内存...

      Start...
      NODE1->NODE2->NODE3
        ^      ^
        |      |
      *temp1 *temp2
      
      temp1 = NODE1;
      temp2 = NODE2;  //or temp2 = temp1->next;
      
      Next...
        +-------------+
        |             V
      NODE1  NODE2->NODE3
        ^      ^
        |      |
      *temp1 *temp2
      
      temp1->next = temp2->next;
      free(temp2);
      
      After...
      NODE1-------->NODE3
      
      //temp1 still = NODE1
      //temp2 = null
      

      让指针对象随您的 while 循环遍历列表,这样您就不会最终不同步。另外一定要检查null

      【讨论】:

        猜你喜欢
        • 2016-03-31
        • 2023-02-25
        • 1970-01-01
        • 1970-01-01
        • 2018-11-15
        • 2013-05-10
        • 2013-01-08
        相关资源
        最近更新 更多