如何修复链表中的分段错误
How to fix Segmentation Fault in linked list
我遇到了一个分段错误,我不知道如何修复。 List.cpp 和 List.hpp 更大,但我添加了我在 main.cpp 中使用的内容。这是代码:
List.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
List.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),所以我不知道在堆栈和堆上创建的变量发生了什么。
如错误(警告)消息所述,在您正在执行的 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{};
在成员函数内部insert
你使用了一个未初始化的指针节点
void List::insert(int value){
Node* node;
^^^^^^^^^^^
node->_value = value;
node->_next = _head;
_head = node;
}
具有不确定的值并尝试使用导致未定义行为的指针访问内存。
您必须分配一个节点,该节点将被指针指向并插入到列表中。
你还忘了增加列表的大小。
但我想指出实施的一些缺点。
初学者不要使用以下划线开头的标识符,因为根据 C++ 标准
(3.2) — Each identifier that begins with an underscore is reserved to
the implementation for use as a name in the global namespace.
所以这样的名字会使代码的读者感到困惑。
结构 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
我遇到了一个分段错误,我不知道如何修复。 List.cpp 和 List.hpp 更大,但我添加了我在 main.cpp 中使用的内容。这是代码:
List.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
List.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),所以我不知道在堆栈和堆上创建的变量发生了什么。
如错误(警告)消息所述,在您正在执行的 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{};
在成员函数内部insert
你使用了一个未初始化的指针节点
void List::insert(int value){
Node* node;
^^^^^^^^^^^
node->_value = value;
node->_next = _head;
_head = node;
}
具有不确定的值并尝试使用导致未定义行为的指针访问内存。
您必须分配一个节点,该节点将被指针指向并插入到列表中。
你还忘了增加列表的大小。
但我想指出实施的一些缺点。
初学者不要使用以下划线开头的标识符,因为根据 C++ 标准
(3.2) — Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
所以这样的名字会使代码的读者感到困惑。
结构 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