【问题标题】:How do I access a null pointer (node) of a linked list?如何访问链表的空指针(节点)?
【发布时间】:2021-08-21 20:22:50
【问题描述】:

这个方法应该在链表的末尾附加一个节点。该方法循环直到到达结尾,也就是空指针。但是当我尝试将空指针更改为一个值时,它会崩溃。我应该如何解决这个问题? (Node指针有一个整数数据和另一个当前Node指向的Node变量)。

void appendItem(LinkedList* list, int value)
{
    Node* temp = (Node*)malloc(sizeof(Node));
    temp = list->head;

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

    temp->data = value;
    temp->next = NULL;
}

【问题讨论】:

  • 在第一行中,您分配内存并将其分配给temp。在下一行中,您将用其他内容覆盖temp。这肯定不是你打算做的事情。
  • while(temp != NULL) --> while(temp->next != NULL) 但你还需要另一个变量,如上所述。

标签: c linked-list append singly-linked-list function-definition


【解决方案1】:

禁止取消引用NULL

取而代之的是,您应该管理一个指向应该更改的内容的指针。

另请注意,通过malloc() 分配一些缓冲区并在之后用另一个值覆盖结果会导致内存泄漏。

还有一点是malloc()family的转换结果是considered as a bad practice

固定代码:

void appendItem(LinkedList* list, int value)
{
    Node** temp = &list->head;

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

    *temp = malloc(sizeof(Node));
    if (*temp != NULL)
    {
        (*temp)->data = value;
        (*temp)->next = NULL;
    }
}

【讨论】:

    【解决方案2】:

    这些行

    Node* temp = (Node*)malloc(sizeof(Node));
    temp = list->head;
    

    产生内存泄漏。首先分配了一块内存,它的地址存储在指针temp 中,然后指针temp 的值被表达式list->head 的值覆盖。结果分配的内存地址丢失了。

    在这个循环之后

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

    指针temp 等于NULL。所以在这些语句中使用空指针来访问内存

    temp->data = value;
    temp->next = NULL;
    

    调用未定义的行为。

    函数可以定义例如下面的方式。

    int appendItem( LinkedList *list, int value )
    {
        Node *new_node = malloc( sizeof( Node ) );
        int success = new_node != NULL;
    
        if ( success )
        {
            new_node->data = value;
            new_node->next = NULL;
    
            if ( list->head == NULL )
            {
                list->head = new_node;
            }
            else
            {
                Node *current = list->head;
                while ( current->next != NULL ) current = current->next;
                current->next = new_node;
            }
        }
    
        return success;
    }
    

    注意内存分配可能会失败。您需要在您的函数中处理这种情况。并且函数的调用者应该被告知这种情况。

    此外,由于您允许将新节点附加到单链表,因此该列表应定义为双边单链表。也就是说,列表应该保留两个指针:一个指向头节点的指针,另一个指向尾节点的指针。否则将节点追加到列表中将是低效的。

    【讨论】:

    • 我认为需要变量success 没有多大意义。如果malloc 失败,为什么不去掉它并简单地return 0,并且总是在函数末尾return 1
    • @AndreasWenzel 该函数正是这样做的。所以你的评论没有意义。唯一的区别是我的函数只有一个 return 语句而不是两个 return 语句。
    • 在编程中很难做到三件事:命名和避免一个错误;)。不错的工作!虽然我会使用表达式while ( NULL != current-next)
    • @AndreasWenzel,这是structured programming 的宗旨之一。一进一出。可以说,当每个函数/方法/过程最后都有一个返回值时,代码审查员会更容易。但是,如果审阅者必须在他们的脑海中携带过多的程序状态,那么它可能会走得太远,从而难以手动验证正确性。但我发现这是简化过于复杂的功能的一个论据。
    • @jwdonahue:每条规则都有例外。虽然通常最好有一个退出,但如果它无法完成其工作,则留在该函数中是没有意义的。在上面的appendItem() 的情况下,用if (list) { } 包装整个函数体来检查指针是否有效是过分的。如果listNULL,则立即返回。功能上无用的块的额外缩进使代码更难阅读。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    相关资源
    最近更新 更多