C 在链表末尾插入

C 在链表末尾插入,c,linked-list,C,Linked List,我编写了一个函数,用于在链表末尾插入一个节点。当我运行程序,调用这个函数时,程序停止工作 以下是函数: void insert(node **head, int x) { node *new = malloc(sizeof(node)); new->data = x; new->next = NULL; node *temp = *head; while (temp != NULL) { temp = temp->ne

我编写了一个函数,用于在链表末尾插入一个节点。当我运行程序,调用这个函数时,程序停止工作

以下是函数:

void insert(node **head, int x) {
    node *new = malloc(sizeof(node));
    new->data = x;
    new->next = NULL;

    node *temp = *head;

    while (temp != NULL) {
        temp = temp->next;
    }
    temp->next = new;
}
谁能告诉我哪里出了问题

  • while
    循环终止时
    temp
    NULL
    。因此
    temp->next
    将生成
    分段错误

    您应该使用
    while(temp->next!=NULL)
    而不是
    while(temp->next!=NULL)

  • 如果
    head
    NULL
    ,该怎么办?(空链接列表)
    为此,请检查
    head
    是否为
    NULL

  • 如果
    malloc
    失败怎么办

  • 因此,解决方案将是:

    void insert(node **head, int x)
    {
        node *new = (node *)malloc(sizeof(node));
        
        if(!new)
        {
            printf("Memory allocation failed!\n");
            exit(1);
        }
        new->data = x;
        new->next = NULL;
    
        node *temp = *head;
    
        if(!temp)
            *head = new;
        else
        {
            while (temp->next != NULL)
            {
                temp = temp->next;
            }
            temp->next = new;
        }
        return ;
    }
    
  • while
    循环终止时
    temp
    NULL
    。因此
    temp->next
    将生成
    分段错误

    您应该使用
    while(temp->next!=NULL)
    而不是
    while(temp->next!=NULL)

  • 如果
    head
    NULL
    ,该怎么办?(空链接列表)
    为此,请检查
    head
    是否为
    NULL

  • 如果
    malloc
    失败怎么办

  • 因此,解决方案将是:

    void insert(node **head, int x)
    {
        node *new = (node *)malloc(sizeof(node));
        
        if(!new)
        {
            printf("Memory allocation failed!\n");
            exit(1);
        }
        new->data = x;
        new->next = NULL;
    
        node *temp = *head;
    
        if(!temp)
            *head = new;
        else
        {
            while (temp->next != NULL)
            {
                temp = temp->next;
            }
            temp->next = new;
        }
        return ;
    }
    

    使用
    节点**
    进行迭代。因此,列表是否为空并不重要。迭代,直到找到其
    next
    NULL
    的节点。您可以按目标分配内存

    void insert( node **head, int x){
    
        node **ptr_new = head;
        while( *ptr_new != NULL ){
            ptr_new = &((*ptr_new)->next);
        }
    
        // now temp refers either to head or to next of the last node.
        *ptr_new = malloc( sizeof(node) );
        if ( *ptr_new != NULL )
        {
            (*ptr_new)->next = NULL;
            (*ptr_new)->data = x;
        }
    }
    
    与原始代码不同,您有一个指向存储新节点地址的指针的指针。在原始版本中,当
    temp
    不是
    NULL
    时,您进行了迭代

    while (temp != NULL) {
        temp = temp->next;
    }
    

    在此之后
    循环
    temp==NULL
    ,因为这是循环的终止条件。因此,您的程序在这里停止工作
    temp->next=new

    使用
    节点**
    进行迭代。因此,列表是否为空并不重要。迭代,直到找到其
    next
    NULL
    的节点。您可以按目标分配内存

    void insert( node **head, int x){
    
        node **ptr_new = head;
        while( *ptr_new != NULL ){
            ptr_new = &((*ptr_new)->next);
        }
    
        // now temp refers either to head or to next of the last node.
        *ptr_new = malloc( sizeof(node) );
        if ( *ptr_new != NULL )
        {
            (*ptr_new)->next = NULL;
            (*ptr_new)->data = x;
        }
    }
    
    与原始代码不同,您有一个指向存储新节点地址的指针的指针。在原始版本中,当
    temp
    不是
    NULL
    时,您进行了迭代

    while (temp != NULL) {
        temp = temp->next;
    }
    

    在此之后
    循环
    temp==NULL
    ,因为这是循环的终止条件。因此,您的程序在这里停止工作
    temp->next=new

    您的代码有两个问题:

    • temp
      指针被推到列表的末尾,直到它变为
      NULL
      ,此时将新指针存储到它的
      下一个
      成员并尝试调用未定义的行为(系统上的
      分段错误
      )为时已晚
    • 如果列表为空,则即使在
      temp->next==NULL
      时停止循环,也无法以这种方式存储新项
    <> P>在C代码中避免使用C++关键字来命名变量,因为如果需要的话,这会使代码迁移到C++更困难。 此外,如果测试
    malloc
    是否失败,并在失败时返回指向新节点的指针或
    NULL
    ,则更为正确

    以下是更正的版本:

    node *insert(node **head, int x) {
        node *new_node = malloc(sizeof(node));
        if (new_node != NULL) {
            new_node->data = x;
            new_node->next = NULL;
    
            node *temp = *head;
            if (temp == NULL) {
                *head = new_node;
            } else {
                while (temp->next != NULL) {
                    temp = temp->next;
                }
                temp->next = new_node;
            }
        }
        return new_node;
    }
    
    您还可以使用指向指针的指针来迭代列表:它稍微复杂一些,但比较短,因为您只有一个测试来找到存储
    指针的位置:

    node *insert(node **head, int x) {
        node *new_node = malloc(sizeof(node));
        if (new_node != NULL) {
            new_node->data = x;
            new_node->next = NULL;
    
            node **np = head;
            while (*np) {
                np = &(*np)->next;
            }
            *np = new_node;
        }
        return new_node;
    }
    

    您的代码有两个问题:

    • temp
      指针被推到列表的末尾,直到它变为
      NULL
      ,此时将新指针存储到它的
      下一个
      成员并尝试调用未定义的行为(系统上的
      分段错误
      )为时已晚
    • 如果列表为空,则即使在
      temp->next==NULL
      时停止循环,也无法以这种方式存储新项
    <> P>在C代码中避免使用C++关键字来命名变量,因为如果需要的话,这会使代码迁移到C++更困难。 此外,如果测试
    malloc
    是否失败,并在失败时返回指向新节点的指针或
    NULL
    ,则更为正确

    以下是更正的版本:

    node *insert(node **head, int x) {
        node *new_node = malloc(sizeof(node));
        if (new_node != NULL) {
            new_node->data = x;
            new_node->next = NULL;
    
            node *temp = *head;
            if (temp == NULL) {
                *head = new_node;
            } else {
                while (temp->next != NULL) {
                    temp = temp->next;
                }
                temp->next = new_node;
            }
        }
        return new_node;
    }
    
    您还可以使用指向指针的指针来迭代列表:它稍微复杂一些,但比较短,因为您只有一个测试来找到存储
    指针的位置:

    node *insert(node **head, int x) {
        node *new_node = malloc(sizeof(node));
        if (new_node != NULL) {
            new_node->data = x;
            new_node->next = NULL;
    
            node **np = head;
            while (*np) {
                np = &(*np)->next;
            }
            *np = new_node;
        }
        return new_node;
    }
    

    您还应该检查
    malloc()
    是否成功,但这项技术很有趣。史蒂夫·马奎尔(Steve Maguire)也用“编写可靠的代码”来描述它。它的优点是避免了特殊情况,因此有助于减少代码膨胀。您还应该检查
    malloc()
    是否成功,但这项技术很有趣。史蒂夫·马奎尔(Steve Maguire)也用“编写可靠的代码”来描述它。它的优点是避免了特殊情况,因此有助于减少代码膨胀。欢迎使用堆栈溢出。一般来说,“只是停止工作”并不是对问题的适当描述。它是否进入无限循环;它是否因分段故障或等效故障而崩溃;还是别的什么?一个需要考虑的问题是“调试器显示了什么?”另一个是“打印语句在添加到代码中时显示了什么?”这些技术中的一个或另一个是解决错误的必要步骤。考虑创建一个MCVE()欢迎堆栈溢出。一般来说,“只是停止工作”并不是对问题的适当描述。它是否进入无限循环;它是否因分段故障或等效故障而崩溃;还是别的什么?其中一个要考虑的问题是“调试器显示了什么?”另一个是“打印语句在添加时显示了什么?”