【问题标题】:Segmentation fault when inserting at the end of a linked list C++在链表C ++的末尾插入时出现分段错误
【发布时间】:2017-03-29 04:01:37
【问题描述】:

好的,所以我正在尝试通过将它们逐一添加到末尾来创建项目的链接列表,并且我还想打印出结果。

我只展示了我的部分代码(我需要处理的部分),所以请忽略我在这个 sn-p 中没有真正使用的所有库:

#include <string>
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

struct Item {
    char letter;
    Item *next;
};

class List {
  public:
    List();
    void InsertEnd(char key);
    void Display();
    bool IsEmpty();
    void SizeOf();
  private:
    Item *head;
    Item *tail;
    int size;
};

List::List() {
    head = NULL;
    tail = NULL;
    size = 0;
}

void List::InsertEnd(char key) {
    //new item we're adding to the end
    Item* addOn = new Item();
    addOn->letter = key;
    addOn->next = NULL;

    //temporary item to traverse through list
    Item* temp = head;

    //if list is empty, head and tail both point to it
    if ( IsEmpty() ) {
        head->next = addOn;
        tail->next = addOn;
    } else {
        //once temp = tail
        if (temp->next == NULL) {
            tail->next = temp;
            temp = addOn;
        }
    }

    //update size of list
    SizeOf();

}

void List::Display() {
    cout << "Items:" << endl;
    for (Item* curr = head->next; curr != NULL; curr = curr->next) {
      cout << curr->letter << endl;
    }

cout << size << " items." << endl;

}

bool List::IsEmpty() {
    if (size == 0)
        return true;
    else 
        return false;
}

void List::SizeOf() {
    size++;
}

int main() {
    List* test = new List;

    test->InsertEnd('A');
    test->InsertEnd('B');
    test->InsertEnd('C');

    test->Display();

    return 0;
}

它编译得很好,但是当我运行它时,我得到的唯一结果就是“分段错误”。 ???

【问题讨论】:

  • 1.您必须发布minimal reproducible example,而不仅仅是您认为错误所在的片段;这是有原因的。 2. 学习使用调试器。调试器回答您的问题比将问题发布到 stackoverflow 更快。

标签: c++ linked-list segmentation-fault


【解决方案1】:

如果列表为空,则 head-&gt;next 将为 NULL,但您却说 head-&gt;next = addOn;。不应该是head = addOn;吗?

事实上,这整段代码都是垃圾:

if ( IsEmpty() ) {
    // head and tail are both null so both of these lines
    // invoke undefined behavior (you cant say NULL->field = something)
    head->next = addOn;
    tail->next = addOn;
} else {
    //once temp = tail
    // temp = head. Shouldn't you just be putting "addOn" as the next item
    // in the list after tail? What if temp->next != NULL?
    if (temp->next == NULL) {
        // tail->next = head (because temp == head). That makes no sense.
        tail->next = temp;
        // So some temp variable = addOn? addOn doesn't actually go into the list?
        // Thats a memory leak right there.
        temp = addOn;
    }
}

在伪代码中你想要的是这样的:

if (IsEmpty())
{
    head = addOn;
    tail = addOn;
}
else
{
    // special case when 1 item in the list (i.e. head == tail)
    if (head == tail)
    {
        // new item comes after head
        head->next = addOn;
    }
    else
    {
        // new item comes after tail
        tail->next = addOn;
    }
    // tail is now the item just added.
    tail = addOn;
}

【讨论】:

  • 好吧,当我构造一个 List 对象时,它已经是空的,因此为什么在我的构造函数中 head 和 tail 都等于 null。 if 语句的意思是,如果我的列表是空的(确实如此),那么我将让 head 和 tail 都指向新项目。 (或者也许我只是没有关注你的问题......但我确实将 head 更改为 = addOn 并且仍然遇到相同的错误:/)
  • 如果head == NULL 你不能做head-&gt;next = anything; 显然同样适用于tail
  • 啊,是的,谢谢!我现在意识到临时项目是完全没有必要的(我在想什么)
【解决方案2】:

我建议您在调试器中单步执行,并在崩溃时准确查看哪个值为 null。调试器将在代码中的每一步向您显示每个值。我已经编程了 30 多年,每天我都会单步执行我的代码。

【讨论】:

  • 这取决于您使用的平台。我在 Mac 上完成所有工作,因此我使用 Xcode,但 Visual Studio for Windows 具有出色的调试器。 gdb 是一款出色的命令行调试器,它几乎可以在您可能使用的任何平台上运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-13
  • 1970-01-01
  • 1970-01-01
  • 2020-09-30
  • 2021-05-04
  • 2022-01-23
相关资源
最近更新 更多