繁体   English   中英

简单的C ++链接列表

[英]Simple C++ Linked List

我有很多以前使用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); } 

首先,在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); 

这不会为除了堆栈之外的任何地方的对象分配空间 - 它非常类似于为堆栈中的intNode *分配空间作为单独的变量。 因此,只要您离开方法,对象就会消失,指向它的指针在使用时会发生奇怪的事情。

第三,要注意:您可能希望在单参数构造函数中设置next = NULL ,以确保它始终具有值。 同样适用于您的默认构造函数。

第四:你的linkedList::print方法循环,​​直到p->nextNULL并打印p->next的值; 如果你想获得第一个和最后一个项目,那么p->next应该可以改为p

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

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

应改为

head = new Node(value, NULL);

对于p->下一个代码也一样。 然后,您将要在析构函数中删除这些节点。

至于印刷试试

while(p != NULL)
{
   cout << p->data << "\n";
   p = p->next;
}

对于初学者

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; }

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

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

一旦您不需要它就可以释放您在堆上分配的所有内容以防止内存泄漏:

delete node;

你没有分配内存。你应该使用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);
                    }
            }

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

  • 当你'新'的对象时,你必须在某个时候'删除'它们。
  • 所有三个构造函数都应初始化两个成员变量。

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

像这样的东西:

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

    while (c != NULL)
    {
        n = c->next;
        delete c;
        c = n;
    }
}

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

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在超出范围时被适当地清理,或者被删除。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM