【问题标题】:C++ Linked List printing CrashC++ 链表打印崩溃
【发布时间】:2017-02-01 16:03:46
【问题描述】:

我不是编程新手,而是学习 C++。为此,我正在用 C++ 语言实现“标准”数据结构。我从链接列表开始。我了解它们的工作原理以及所有这些。但是,当我尝试打印出列表时,它并没有在它应该停止的时候停止。我将最后一个指针设置为 nullptr 和所有这些,并在互联网上大量研究了这个问题,但我找不到我正在做的与其他人不同的事情。代码如下:

template<typename T>
void LinkedList<T>::print_list(){

    list_node<T> *pos = this->start;

    while(pos != nullptr){
       cout << "PRInting" <<pos->data<<endl <<pos->next;

        pos = pos->next;
    }
}

这是完整的代码:

#ifndef LINKEDLIST_H_INCLUDED
#define LINKEDLIST_H_INCLUDED

#include <iostream>

using std::cout;
using std::endl;
template <class T>
struct list_node{
    T data;
    list_node<T> *next;
};
template <class T>
class LinkedList{
private:
    list_node<T> *start;

public:
    LinkedList();
    LinkedList(T firstData);
    ~LinkedList();
    void insert_item(T item);
    void delete_item(T item);
    list_node<T>* search_list();
    void print_list();
};



//constructors and destructor
template <typename T>
LinkedList<T>::LinkedList(){
    this->start = nullptr;
}
template <typename T>
LinkedList<T>::LinkedList(T firstData){
    list_node<T> newNode = {
        firstData,
        nullptr
    };
    this->start = &newNode;
    cout <<"Constructor" <<this->start->data<<endl;
}
template <typename T>
LinkedList<T>::~LinkedList(){
    this->start = nullptr;
}

//Debugging print function
template<typename T>
void LinkedList<T>::print_list(){
    list_node<T> *pos = this->start;
    while(pos != nullptr){
        cout << "PRInting" <<pos->data<<endl <<pos->next;
        pos = pos->next;
    }
    //cout << pos->data;
}


//Operations on Linked Lists
template <typename T>
void LinkedList<T>::insert_item(T item){
    list_node<T> *insertNode;
    insertNode->data = item;
    insertNode->next = this->start;
    this->start = insertNode;
    cout << "After insert " <<this->start->data << '\n' << this->start->next->data<<endl;
}

#endif // LINKEDLIST_H_INCLUDED

【问题讨论】:

  • 我将最后一个指针设置为 nullptr 从给出的示例中我们看不到这一点。请提供minimal reproducible example
  • 这个功能对我来说看起来不错。问题肯定出在其他地方。
  • 如果您在崩溃前最后输出的行不是 0,那么您就没有空终止列表
  • 其中一些 cout 语句仅用于我的调试目的。

标签: c++ data-structures linked-list


【解决方案1】:

您的代码中存在两个关于节点插入的不同问题。

  1. 在您的构造函数中:您正在创建一个局部变量newNode,并将其内存地址存储在this-&gt;start 中。但是,newNode 对象将在离开构造函数的范围时被销毁,并且尝试取消引用它会导致 UB(未定义行为)。您应该动态分配节点,因此一旦离开范围就不会被破坏:

    LinkedList<T>::LinkedList(T firstData){
        this->start = new list_node<T>;
        this->start->data = firstData;
        this->start->next = nullptr;
        cout <<"Constructor" <<this->start->data<<endl;
    }
    
  2. 在您的 insert_item 过程中:您正在取消引用本地指针 insertNode,即使没有为其分配实际内存,并且取消引用它也会导致 UB。正确的版本如下所示:

    template <typename T>
    void LinkedList<T>::insert_item(T item){
        list_node<T> *insertNode = new list_node<T>;
        insertNode->data = item;
        insertNode->next = this->start;
        this->start = insertNode;
        cout << "After insert " <<this->start->data << '\n' << this->start->next->data<<endl;
        }
    
  3. 现在,由于我们正在进行动态内存分配,我们需要在析构函数中释放它(C++ 没有垃圾收集),所以简单地将start 分配给nullptr 是不够的:

    template <typename T>
        LinkedList<T>::~LinkedList(){
            list_node<T> *pos = this->start;
            while (pos != nullptr){
                list_node<T>* nextPos = pos->next;
                delete pos;
                pos = nextPos;
            }
        }
    

【讨论】:

  • 比我的答案更好,所以我将附带评论:与其使用虚拟节点作为链表的末尾,不如考虑设置最后一个节点的下一个成员@ 987654332@ 并对此进行测试。使用更少的存储空间和更少的node-&gt;next 迭代。一个简单的开始方法是向list_node 添加一个构造函数:list_node(T &amp; data) : data(data), next(nullptr){} 现在创建的每个节点都有数据并且开始指向没有下一个节点,您可以将它放在列表的末尾或开头或不用担心忘记结束列表。
  • 那行得通。谢谢。而且,如果我为了我自己的缘故可以澄清一下。 'new' 关键字动态分配内存。如果内存不是为对象动态分配的,一旦超出范围就会被销毁?
  • @Shadow1356 你明白了。只要记住deletenewSmart pointers can help with this
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多