问题描述
我遇到了一个细分错误,我不知道该如何解决。 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;
但这只是声明了一个尚未指向有效内存的指针。访问对象的成员,例如_value
指向的node
,将调用未定义的行为。这可能会导致分段错误。如果您不走运,则不会出现段错误,该程序将在以后的某个时间点中断。
您需要像这样为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;
};
此外,似乎不需要为List
中的main
分配内存:
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)-每个以下划线开头的标识符都保留给 在全局命名空间中用作名称的实现。
因此,这样的名称会使您的代码阅读者感到困惑。
结构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