【问题标题】:Debugging linked list pointers code: segmentation fault调试链表指针代码:分段错误
【发布时间】:2020-08-07 21:02:00
【问题描述】:

所以下面的代码:

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

所以,基本上我想在链表“头”的末尾添加“数据”并返回更新后的列表。那么错在哪里呢?

编辑:好的,我遇到了第一个错误。但是即使我在循环条件中将 temp!=NULL 替换为 temp->next!=NULL 仍然存在这个错误

【问题讨论】:

  • SinglyLinkedListNode* temp1; temp1->data=data; 不起作用,temp1 指向哪里?
  • @mch,好吧,我是新手。我的想法是我应该初始化一个空白变量,就像我们将整数声明为“int a; a=2;”一样。那么我该如何解决呢?
  • tempwhile(temp!=NULL) 循环之后的值是多少?
  • @molbdnilo,指向链表最后一个节点的指针?
  • 不只是temp1,temp指向哪里? (NULL)

标签: c++ pointers linked-list append singly-linked-list


【解决方案1】:

这里也崩溃了:

SinglyLinkedListNode* temp1;
temp1->data=data;

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

【讨论】:

  • 谢谢,请查看修改,并请说明为什么会崩溃?
【解决方案2】:

您必须为节点分配内存。记得清理分配的内存。每次拨打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;
}

【讨论】:

  • @AdityaAgarwal 指针可以隐式转换为布尔值,nullptr 返回 false,否则返回 true。 !head 等价于 head == nullptr
  • 好的,谢谢!我明白你所说的一切。但是当我使用你的代码时,出现以下错误:错误:没有匹配函数调用'SinglyLinkedListNode::SinglyLinkedListNode()'
  • @AdityaAgarwal 这意味着您没有默认构造函数。您必须在此时调用您的构造函数之一。
  • @AdityaAgarwal 指针值被评估为真,当且仅当它不是 nullptr,所以 '''!head''' 为真,如果 head IS nullptr
  • *temp 上的任何更改也会发生在*head 上。
【解决方案3】:

这个函数

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

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

请记住,如果您有一个单链表并且想要将新节点附加到列表 10 的尾部,则最好定义双边单链表。在这种情况下,列表定义可能如下所示

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

【讨论】:

    猜你喜欢
    • 2012-11-19
    • 2020-08-14
    • 2018-07-23
    • 2016-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-07
    • 2013-09-18
    相关资源
    最近更新 更多