7

我以前在 Java 中使用链表有很多经验,但我似乎对 C++ 中的这种简单尝试感到困惑。我在运行时遇到分段错误,据我了解,这与分配空指针有关,但我对解决方案不知所措。

编辑:谢谢大家非常有帮助的回复。该代码现在正在运行,但正在尝试使用

delete p;
在linkedList::addNode 的末尾会导致运行时出现分段错误。只是好奇是否有人知道这是为什么?

这是我更新的代码:

#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);
}
4

9 回答 9

6

首先,在linkedList::addNode方法中,你有结构if (head = NULL),它最终会分配head; 你想要==运营商。

二、关于线路:

head = &(Node (value, NULL));

由于有些不直观的原因,这行不通。您将获得对 a 的引用Node,但该节点将在方法结束后立即超出范围,并且尝试引用它会导致分段错误。您需要使用new运算符(与其他类似行相同):

head = new Node(value, NULL);

如果您添加了删除节点的方法,请确保delete该节点当时 - 它不会像在 Java 中那样自动进行垃圾收集。

边栏:想想会发生什么:当你这样做时Node(value, NULL),你正在使用一个像这样声明的临时变量:

Node hiddenTempNode(value, NULL);

这不会在堆栈上以外的任何地方为对象分配空间——它非常类似于在堆栈上为 anint和 a分配空间Node *作为单独的变量。结果,一离开方法,对象就消失了,指向它的指针在使用时会做一些奇怪的事情。

第三,请注意:您可能希望next = NULL在单参数构造函数中进行设置,以确保它始终具有值。对于您的默认构造函数也是如此。

第四:您的linkedList::print方法正在循环直到p->nextisNULL并打印p->next; 如果你想获得第一个和最后一个项目,那些出现的p->next可能应该更改为。p

于 2009-07-08T03:16:19.687 回答
3

您正在获取堆栈上变量的地址

head = &(Node (value, NULL));

应该改为

head = new Node(value, NULL);

p->next 代码相同。然后你会想要在你的析构函数中删除这些节点。

至于印刷尝试

while(p != NULL)
{
   cout << p->data << "\n";
   p = p->next;
}
于 2009-07-08T03:15:26.630 回答
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; }
于 2009-07-08T03:14:01.063 回答
2

您正在为堆栈上的节点分配空间并获取其地址,一旦块结束,地址就会消失,因此地址将变为无效。new您应该在堆上使用运算符分配节点:

Node* node = new Node(value, NULL);

您应该在不需要时立即释放在堆上分配的所有内容以防止内存泄漏:

delete node;
于 2009-07-08T03:14:33.027 回答
1

我想补充两个尚未提及的问题:

  • 当您“新建”对象时,您必须在某个时候“删除”它们。
  • 所有三个构造函数都应该初始化两个成员变量。
于 2009-07-08T03:22:48.100 回答
1

您的 delete 语句实际上并没有进行任何清理。到你称它为 p==null 的时候。如果要清理列表,则需要实现一个单独的方法来迭代并删除每个节点。

像这样的东西:

void ClearList ()
{
    Node * c = head;
    Node * n;

    while (c != NULL)
    {
        n = c->next;
        delete c;
        c = n;
    }
}
于 2009-07-08T03:55:35.760 回答
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);
                    }
            }
于 2009-07-08T03:15:14.197 回答
0

该代码现在正在运行,但正在尝试使用

delete p;

在linkedList::addNode 的末尾会导致运行时出现分段错误。只是好奇是否有人知道这是为什么?

这是一个问题,因为添加节点函数的目的是在 LinkedList 的末尾动态分配一个新节点。所以你正确地做到了,现在通过输入'删除p;' 您正在删除新添加的节点(我想您实际上并不想要)。但是,要回答您的问题,这就是导致分段错误的原因:

你添加一个节点,你告诉 head 指向这个新节点。现在你删除了这个新节点,但没有告诉 head 它应该再次指向 NULL。因此,下次添加节点或尝试打印列表时,它会立即尝试查看头指向的内容,实际上是释放(删除)内存,kaboom?

列表中删除的正确(或至少一个正确)用法是在析构函数中,请记住,在 C++ 中,我们总是希望清理已分配的动态内存,您的析构函数可能如下所示:

~linkedList()
{
    Node* p = head;
    while ( p!=NULL )
    {
        Node* nextNode = p->next;
        delete p;
        p = nextNode;
    }
}

通过使用像这样的析构函数,您可以保证您的linkedList 在超出范围或被删除时会被适当地清理。

于 2009-07-08T05:27:08.493 回答
-2

解决方案:不要实现自己的链表。使用标准库提供的那个。

于 2009-07-08T03:30:32.330 回答