尝试从链表中删除最后一个元素并将其保存到作为参数传递的变量中,给出段错误

Trying to remove last element from linked list and save it into a variable passed as parameter giving segfault

我有一个链表,我试图在其中删除最后一个 char* 元素,并将我传递给该函数的参数设置为 char*。但是,这要么会出现段错误,要么会打印出乱码。为什么会这样?

链表如下:

  struct list_node {
          char* name;
          struct list_node* next;
  };
  typedef struct list_node node;

下面是它的功能(我很确定其他功能有效但 remove_last 无效):

  int remove_last(node* head, char* ret) {
          while(head) {
                  if (head->next->next == NULL) {
                          printf("here\n");
                          ret = strdup(head->next->name);
                          printf("%s\n", ret);
                          printf("there\n");
                          //free(head->next);
                          //head->next = NULL;
                          return 0;
                  }
                  head = head->next;
          }
          return -1;
  }

  void add_last(char* name, node* current) {
          node* new_node;
          new_node = (node*)malloc(sizeof(node));
          while(current) {
                  if (current->next == NULL) {
                          current->next = new_node;
                          new_node->name = name;
                          return;
                  }
                  current = current->next;
          }
  }

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

在函数内部,当我 printf ret 时,我得到了我应该得到的,但是在我的 main 中,当我尝试打印出传递给参数的 ret 变量时:

char *temp = NULL;
remove_last(head, temp);
printf("%s\n", temp);

我遇到段错误。我最初认为可能是因为我正在设置节点并释放它们,但我也使用了 strdup(我认为它会将它复制到新位置或类似的东西?)。我认为这也可能与我如何将 temp 设置为 null 然后我没有在函数中正确设置分配 ret = name 有关?有什么建议吗?

对于初学者来说,函数 add_last 是不正确的,可以调用未定义的行为。

首先它不检查指针current(我想它可以是指向头节点的指针)是否等于NULL。在这种情况下存在内存泄漏,因为新创建的节点未附加到列表中。

其次函数没有设置新建节点的数据成员nextNULL

如果要使用您的方法来实现函数,至少可以按以下方式声明和定义函数 add_first

node * add_last(char* name, node *head ) {
    node* new_node; 
    new_node = (node*)malloc(sizeof(node));
    new_node->name = name;
    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;
}

至于函数remove_last那么函数参数ret是函数的局部变量,退出函数后不会存活。函数参数的类型必须为 char **。即相应的参数必须通过引用传递给函数。

并且在任何情况下该函数都是不正确的,因为它忽略了列表仅包含一个节点的情况。您还需要通过引用将指针传递给头节点。

函数可以如下所示。

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;
}