我有很多以前使用Java链接列表的经验,但我似乎对这种在C ++中的简单尝试感到困惑。我在运行时遇到了一个分段错误,根据我的理解,它与分配一个空指针有关,但是我对解决方案感到茫然。
编辑:谢谢大家的回复。代码现在正在运行,但是尝试在linkedList :: addNode的末尾使用
delete p;
会在运行时导致分段错误。只是好奇,如果有人知道为什么会这样吗?
这是我更新的代码:
#include <iostream>
using namespace std;
class Node{
public:
int data;
Node * next;
Node(int x){
data = x;
next = NULL;
}
Node(int x, Node * y){
data = x;
next = y;
}
};
class linkedList{
Node *head;
public:
linkedList(){
head = NULL;
}
void addNode(int value){
Node *p;
if(head == NULL)
head = new Node (value, NULL);
else{
p=head;
while(p->next !=NULL)
p=p->next;
p->next = new Node (value, NULL);
}
}
void print(){
Node * p;
p = head;
while(p != NULL){
cout << p->data << "\n";
p = p->next;
}
}
};
int main(void){
linkedList test;
test.addNode(4);
test.addNode(76);
test.addNode(12);
test.print();
return(0);
}
答案 0 :(得分:6)
首先,在linkedList::addNode
方法中,您有一个构造if (head = NULL)
,它将分配到head
;你想要==
运算符。
第二,关于这一行:
head = &(Node (value, NULL));
出于某种不直观的原因,这不起作用。您将获得对Node
的引用,但该方法一旦该方法结束就会超出范围,并且尝试引用它将导致分段错误。您需要使用new
运算符(与其他类似行相同):
head = new Node(value, NULL);
如果添加一个删除节点的方法,请确保delete
节点 - 它不会像在Java中那样自动进行垃圾收集。
补充工具栏:想想会发生什么:当你执行
Node(value, NULL)
时,你正在使用一个像这样声明的临时变量:Node hiddenTempNode(value, NULL);
除了堆栈之外,它不会为对象分配空间 - 它非常类似于为堆栈上的
int
和Node *
分配空间作为单独的变量。因此,只要您离开该方法,对象就会消失,指向它的指针在使用时会发生奇怪的事情。
第三,要注意:您可能希望在单参数构造函数中设置next = NULL
,以确保它始终具有值。同样适用于您的默认构造函数。
第四:您的linkedList::print
方法正在循环,直到p->next
为NULL
并打印p->next
的值;如果您想获得第一个和最后一个项目,p->next
的出现次数可能应该更改为p
。
答案 1 :(得分:3)
你正在获取堆栈上的变量地址
head = &(Node (value, NULL));
应改为
head = new Node(value, NULL);
对于p->下一个代码,相同。然后,您将要在析构函数中删除这些节点。
至于印刷试试
while(p != NULL)
{
cout << p->data << "\n";
p = p->next;
}
答案 2 :(得分:2)
首发
if(head = NULL)
是一项任务,而不是对平等的检查。将其更改为
if(head == NULL)
其次,
head = &(Node (value, NULL));
没有意义*将此更改为
head = new Node (value, NULL);
*这实际上会创建一个临时对象,为您提供地址,然后销毁新创建的对象。
第三,
Node(int x) { data = x; }
保留next
没有值,将此行更改为
Node(int x) { data = x; next = NULL; }
答案 3 :(得分:2)
您正在为堆栈上的节点分配空间并抓取其地址,一旦块结束,该地址就会消失,因此地址将变为无效。您应该在堆上使用new
运算符分配节点:
Node* node = new Node(value, NULL);
一旦你不需要它就可以释放你在堆上分配的所有内容以防止内存泄漏:
delete node;
答案 4 :(得分:1)
你没有分配内存。你应该用new来分配它。
if(head = NULL)中还有一个错误,它应该是if(head == NULL)
void addNode(int value){
Node *p;
if(head == NULL)
head = new Node (value, NULL);
else{
p=head;
while(p->next !=NULL)
p=p->next;
p->next = new Node (value, NULL);
}
}
答案 5 :(得分:1)
我想补充两个未提及的问题:
答案 6 :(得分:1)
您的删除语句实际上没有进行任何清理。当你调用它时,p == null。如果要清理列表,则需要实现一个单独的方法来迭代,并删除每个节点。
这样的事情:
void ClearList ()
{
Node * c = head;
Node * n;
while (c != NULL)
{
n = c->next;
delete c;
c = n;
}
}
答案 7 :(得分:0)
代码现在正在运行,但正在努力 使用
delete p;
在linkedList :: addNode的末尾 导致分段错误 运行。只是好奇,如果有人知道 为什么会这样?
这是一个问题,因为添加节点功能的目的是在LinkedList的末尾动态分配一个新节点。所以你正确地做到了,现在把'删除p;'你正在删除新添加的节点(我想你实际上并不想要的东西)。但是,要回答您的问题,这就是导致分段错误的原因:
你添加一个节点,你告诉head指向这个新节点。现在你删除这个新节点而不告诉它应该再次指向NULL。因此,下次添加节点或尝试打印列表时,它会立即尝试查看指向哪个头,实际上是释放(删除)的内存,kaboom?
列表中删除的正确(或至少一个正确)用法是在析构函数中,记住在C ++中我们总是希望清理我们分配的动态内存,析构函数可能如下所示:
~linkedList()
{
Node* p = head;
while ( p!=NULL )
{
Node* nextNode = p->next;
delete p;
p = nextNode;
}
}
通过使用这样的析构函数,可以保证linkList在超出范围时被适当地清理,或者被删除。
答案 8 :(得分:-2)
解决方案:不要实现自己的链接列表。使用标准库提供的那个。