调试链表指针代码:segmentation fault

Debugging linked list pointers code: segmentation fault

所以下面的代码:

/*
 * For your reference:
 *
 * SinglyLinkedListNode {
 *     int data;
 *     SinglyLinkedListNode* next;
 * };
 *
 */
SinglyLinkedListNode* insertNodeAtTail(SinglyLinkedListNode* head, int data) {
  SinglyLinkedListNode* temp = head;
  while (temp != NULL) {
    temp = temp->next;
  }
  SinglyLinkedListNode* temp1;
  temp1->data = data;
  temp1->next = NULL;
  temp->next = temp1;
  return temp;
}

所以,基本上我想在链表 "head" 和更新列表的末尾添加 "data" 和 return 。那么错在哪里呢?

编辑:好的,我犯了第一个错误。但即使我在循环条件中用 temp->next!=NULL 替换 temp!=NULL 仍然存在此错误

这里也崩溃了:

SinglyLinkedListNode* temp1;
temp1->data=data;

当您到达循环的末尾 while(temp!=NULL){ 时,这里的 tempNULL。 下面你正在使用这样的语句 temp->next=temp1; 这会导致崩溃

您必须为节点分配内存。记得清理分配的内存。对于 new 的每次调用,您都需要调用 delete。所以我更喜欢智能指针。

在你的循环 temp 包含 NULL 之后。您不能取消引用空指针。

SinglyLinkedListNode* insertNodeAtTail(SinglyLinkedListNode* head, int data) {
    SinglyLinkedListNode* temp1 = new SinglyLinkedListNode;
    temp1->data = data;
    temp1->next = nullptr;
    if (!head) {
        head = temp1;
        return head;
    }
    SinglyLinkedListNode* temp = head;
    while(temp->next){
        temp = temp->next;
    }
    temp->next = temp1;
    return temp;
}

这个函数

SinglyLinkedListNode* insertNodeAtTail(SinglyLinkedListNode* head, int data) {
SinglyLinkedListNode* temp=head;
while(temp!=NULL){
    temp=temp->next;
}
SinglyLinkedListNode* temp1;
temp1->data=data;
temp1->next=NULL;
temp->next=temp1;
return temp;
}

没有意义。在这个循环之后

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

指针temp等于NULL。所以这个声明

temp->next=temp1;

调用未定义的行为。

指针 temp1 未初始化。所以这些陈述再次

temp1->data=data;
temp1->next=NULL;

调用未定义的行为。

函数的使用者并不知道返回的指针是链表的头指针还是尾指针。所以不清楚是把返回的指针赋值给头指针还是直接忽略返回值

函数可以如下所示。

void insertNodeAtTail( SinglyLinkedListNode * &head, int data ) 
{
    SinglyLinkedListNode **current = &head;

    while ( *current != nullptr ) current = &( *current )->next;

    *current = new SinglyLinkedListNode { data, nullptr };
}

如果在 main 中定义了指向头节点的指针,例如

SinglyLinkedListNode *head = nullptr;

那么函数调用会像这样

insertNodeAtTail( head, some_data );

函数的另一种定义方式如下

SinglyLinkedListNode* insertNodeAtTail( SinglyLinkedListNode *head, int data ) 
{
    SinglyLinkedListNode *new_node = new SinglyLinkedListNode { data, nullptr };

    if ( head == nullptr )
    {
        head = new_node;
    }
    else
    {
        SinglyLinkedListNode *current = head;

        while ( current->next != nullptr ) current = current->next;

        current->next = new_node;
    }

    return head;
}

在这种情况下,如果您在 main 中定义了指向头节点的指针,例如

SinglyLinkedListNode *head = nullptr;

那么函数调用看起来像

head = insertNodeAtTail( head, some_data );

在这两个函数定义之间,第一个函数定义更可取,因为不需要记住将返回的指针分配给头节点。

请记住,如果您有一个单向链表并希望将新节点附加到链表十的尾部,最好定义双向单向链表。在这种情况下,列表定义看起来像

class SinglyLinkedList
{
private:
    struct Node
    {
        int data,
        Node *next;
    } *head = nullptr, *tail = nullptr;

public:

    SinglyLinkedList() = default;
    void insertNodeAtHead( int data );
    void insertNodeAtTail( int data );
    // other member functions;
};