【问题标题】:How to fix Segmentation Fault in linked list如何修复链表中的分段错误
【发布时间】:2020-12-07 22:08:00
【问题描述】:

我遇到了不知道如何解决的分段错误错误。 List.cpp 和 List.hpp 更大,但我只添加了我在 main.cpp 中使用的内容。代码如下:

列表.hpp

#ifndef LIST_H
#define LIST_H

#include <iostream>
#include <cstdlib>

struct Node{
    int _value;
    Node *_next;
};

struct List{
    Node *_head;
    int _size;

    List();
    void insert(int value);
    void print();
};

#endif

列表.cpp

#include "List.hpp"

List::List(){
    _size = 0;
    _head = nullptr;
}

void List::insert(int value){
    Node* node;
    node->_value = value;
    node->_next = _head;
    _head = node;
}

void List::print(){
    Node* head = _head;
    if (_size > 0){
        while(head){
            std::cout << head->_value << " ";
            head = head->_next;
        }
        std::cout<<std::endl;
    }
    else{
        std::cout<<std::endl;
        return;
    }
}

main.cpp

#include <iostream>
#include "List.hpp"

int main(){
    List *L = new List();
    int N=0;
    std::cout << "type the N value"<< std::endl;
    std::cin >> N;

    for(int i=0; i<=N; i++){
        L->insert(i);
    }

    L->print();
    delete L;
    return 0;
}

控制台

▶ g++ -std=c++14 -Wall main.cpp List.cpp -o main && ./main out
List.cpp: In member function ‘void List::insert(int)’:
List.cpp:10:15: warning: ‘node’ is used uninitialized in this function [-Wuninitialized]
   10 |  node->_value = value;
      |  ~~~~~~~~~~~~~^~~~~~~
type the N value
3
[1]    13247 segmentation fault (core dumped)  ./main out

我实际上也不知道如何调试它(我正在使用 VS Code),所以我不知道在堆栈和堆上创建的变量发生了什么。

【问题讨论】:

  • 当您尝试访问无效的内存地址时会发生这种情况。也许您在使用它之前没有分配内存,或者您正在访问您的程序不允许访问的内存。
  • 编译器正在告诉问题。 node 是未初始化的指针。它指向什么?

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


【解决方案1】:

在成员函数insert 内部,您使用的是未初始化的指针节点

void List::insert(int value){
    Node* node;
    ^^^^^^^^^^^
    node->_value = value;
    node->_next = _head;
    _head = node;
}

具有不确定值并尝试使用此指针访问内存会导致未定义的行为。

您必须分配一个将被指针指向并插入到列表中的节点。

你也忘了增加列表的大小。

但我想指出实现的一些缺点。

根据 C++ 标准,请不要使用以下划线开头的标识符

(3.2) — 每个以下划线开头的标识符都保留给 在全局命名空间中用作名称的实现。

所以这样的名字会让你的代码的读者感到困惑。

结构Node 应该是结构List 的私有或受保护数据成员。用户不能直接访问结构节点。这是一个实现细节。

动态分配 List 类型的对象是没有意义的。

这是一个演示程序,展示了如何实现该列表。

#include <iostream>
#include <functional>

class List
{
protected:
    struct Node
    {
        int value;
        Node *next;
    } *head = nullptr;

    size_t n = 0;

public: 
    List() = default;
    ~List() { clear(); }
    
    //  These special member functions you can define yourself if you will want
    List( const List & ) = delete;
    List & operator =( const List & ) = delete;
    

    void insert( int value );

    size_t size() const { return n; }
    
    void clear()
    {
        while ( head ) delete std::exchange( head, head->next );
        n = 0;
    }
    
    friend std::ostream & operator <<( std::ostream &os, const List &list )
    {
        for ( Node *current = list.head; current != nullptr; current = current->next )
        {
            os << current->value << " -> ";
        }
        
        return os << "null";
    }
};

void List::insert( int value )
{
    head = new Node { value, head };
    ++n;
}

int main() 
{
    const int N = 10;
    
    List list;
    
    for ( int i = N; i != 0; i-- )
    {
        list.insert( i );
    }
    
    std::cout << list << '\n';
    
    return 0;
}

程序输出是

1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> null

【讨论】:

    【解决方案2】:

    正如错误(警告)消息所说,在您正在执行的 insert 函数中:

    Node* node;
    

    但这只是声明了一个尚未指向有效内存的指针。访问对象的成员,例如node 指向的_value,将调用未定义的行为。这可能会导致分段错误。如果运气不好,不会有段错误,程序会在稍后的某个时间中断。

    您需要像这样为Node 分配内存:

    Node* node = new Node{};
    

    事实上,整个insert 函数可以简单地是:

    void List::insert(int value) {
        _head = new Node{value, _head};  // allocate Node, initialize to
                                         // appropriate values, and link _head
    }
    

    另外,你应该像这样默认初始化Node 的成员:

    struct Node{
        int _value{};
        Node *_next = nullptr;
    };
    

    另外,似乎没有必要为main 中的List 分配内存:

    List *L = new List();
    

    相反,您可以像这样简单地拥有一个 List 对象:

    List L{};
    

    【讨论】:

      猜你喜欢
      • 2019-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-03
      • 2012-09-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多