释放链表内的 strdup

问题描述

我有一个链表,我试图在其中释放我使用 char*strdup

这些是我将节点添加到列表中的方法

  node* add_first(char* name,node* head) {
          node* new_node;
          new_node = (node*)malloc(sizeof(node));
          char* c = strdup(name);
          new_node->name = c;
          new_node->next = head;
          head = new_node;
          return head;
  }

node * add_last(char* name,node *head ) {
      node* new_node;
      node* current;
      new_node = (node*)malloc(sizeof(node));
      char* c = strdup(name);
      new_node->name = c;
      new_node->next = NULL;

      if ( head == NULL ){
              head = new_node;
      }
      else{
              current = head;
              while ( current->next ) current = current->next;
              current->next = new_node;
      }

          return head;
  }

用于删除节点:

 int remove_last( node **head,char **ret )
  {
          int result = *head == NULL ? -1 : 0;

          if ( result == 0 )
          {
                  while( ( *head )->next != NULL ) head = &( *head )->next;

                  *ret = strdup( ( *head )->name );
                  free( *head );
                  *head = NULL;
          }

          return result;
  }

为了清理列表:

void deleteList(node** head){
      node* current = *head;
      node* next;

      while(current != NULL){
              next = current->next;
              free(current->name);
              free(current);
              current = next;
      }

      *head = NULL;
  }

但是 valgrind 说,当涉及到 strdup 函数中的 add_last 时,我“绝对失去了”记忆(但奇怪的是我的 add_first 函数没有)。

为什么它只发生在 add_last 方法上,我该如何正确释放它?我以为我正在释放 deleteList 方法中的所有节点和名称

解决方法

您不必要地复制了最后一个节点删除算法中的字符串,并泄漏了原始字符串。该算法应该找到列表中的最后一个节点,将 name 指针的所有权传递给 out-param,然后删除节点而不删除名称(因为 out-param 现在拥有它)。

即你应该按照这些方式做一些事情(公平警告,没有经过编译测试,但你希望能明白这个想法):

int remove_last( node **head,char **ret )
{
    int res = -1;
    if (*head)
    {
        // find last node in the list
        while ((*head)->next)
            head = &(*head)->next;

        // out-param takes ownership
        *ret =(*head)->name;

        // free last node *without* freeing the string
        free(*head);
        *head = NULL;

        // result indicates success
        res = 0;
    }
    return res;
}