双向链表“未处理的异常”错误

时间:2017-03-20 16:19:04

标签: c++ data-structures linked-list

我正在创建一个双链表,我得到一个奇怪的错误,花了好几个小时来调试但是没有这样做,尝试了一个在线调试器,甚至没有帮助

程序确实编译并运行,但崩溃了我得到的错误

  

双链接list.exe中0x770215ee处的未处理异常:0xC0000005:访问冲突写入位置0x00000004。

在线调试程序结果http://onlinegdb.com/Bkta6O6ig

在线调试器提供了三个错误,我在下面的代码中提到了注释

我的猜测是类列表的添加功能有问题

班级节点

#include <iostream>

using namespace std;

class node
{
private:

    int data;
    node *prev_pointer;
    node *next_pointer;

public:

    int get_data()
    {
        return data;
    }

    void set_data(int data)
    {
        this->data = data;
    }



    node* get_prev_ptr()
    {
        return prev_pointer;
    }

    void set_next_ptr(node *Node)
    {
        next_pointer = Node;
    }

    node* get_next_ptr()
    {
        return next_pointer;
    }


    void set_prev_ptr(node *hi)
    {
        prev_pointer = hi;   //First error
    }
};

班级列表

class List
{
private:

    int size;
    node * cursor; 
    node * lastnode;
    node * headnode; 

public:

    List();
    void add(int data);
    bool next();
    void previous();
    void start();
    void traverse();
    int get_data();
//  ~List();
};

List :: List()
{
    headnode = new node();
    cursor = NULL;
    lastnode = NULL;
    size = 0;
}

void List:: add(int data)
{
    node *newnode = new node();
    newnode->set_data(data);

        if ( cursor != NULL )
        {
            newnode->set_next_ptr(cursor->get_next_ptr());
            newnode->set_prev_ptr(cursor);
            (newnode->get_next_ptr())->set_prev_ptr(newnode);  //2nd error
            cursor->set_next_ptr(newnode);
            lastnode = cursor; 
            cursor = cursor->get_next_ptr();
        }
        else 
        {
            newnode->set_next_ptr(NULL);
            newnode->set_prev_ptr(headnode);
            headnode->set_next_ptr(newnode);
            cursor = newnode;
            lastnode = headnode;
        }

    size++;
}

bool List :: next()
{
    if ( cursor != NULL )
    {
        return false;
    }
    else
    {
        lastnode = cursor;
        cursor = cursor->get_next_ptr();
    }

    if( cursor == NULL || size == 0 )
        return false;
    else 
        return true;
}

void List :: traverse()
{
    node *temp = cursor;
    start();

    for ( int i = 0 ; next() ; i++ )
    {
        cout<<"element  " << i << "  " << cursor->get_data() <<endl;
    }
}

void List :: start()
{
    lastnode = headnode;
    cursor = headnode;
}

int List :: get_data()
{
    return cursor->get_data();
}

主要

int main()
{
    List list;
    list.add(10);
    list.add(11);         //3rd error 
    list.add(12);
    //list.add(13);
    //list.add(14);
    //list.add(15);

    list.traverse();

    return 0;
}

1 个答案:

答案 0 :(得分:3)

预付:阅读debuger输出:

Program received signal SIGSEGV, Segmentation fault.                                          
0x0000000000400d20 in node::set_prev_ptr (this=0x0, hi=0x614c60) at main.cpp:46               
46                      prev_pointer = hi; 

注意this=0x0。所有类方法都有一个this指针,以便它们知道要操作的许多可能实例中的哪一个。这里this指向NULL。程序无法从NULL对象获取有效的prev_pointer。这告诉您,要找到问题的真正原因,您需要找出this无效的原因。

这就是callstack进来的地方。你向后移动堆栈以找出this被摧毁的地方。我们可以看到在set_prev_ptrget_next_ptr的输出上调用get_next_ptr uis会返回next_pointer。首先要看的是next_pointer。将newnode->next_pointer放入&#34;显示表达式&#34;表明next_pointer为NULL。

为什么next_pointer为空呢?我们找到几行代码

newnode->set_next_ptr(cursor->get_next_ptr())

所以我们查看cursor->next_pointer并发现它是NULL。现在我们进入原始帖子并绘制链接列表,因为它比一遍又一遍地运行和重新运行调试器要快得多。

调试链表的最佳方法是使用铅笔和纸张:绘制它。添加10后,您会看到列表看起来像

head <-> 10 -> NULL
cursor -> 10 -> NULL
lastnode -> 10 -> NULL

添加11应该看起来像

head <-> 10 <-> 11 -> NULL
cursor -> 11 -> NULL
lastnode -> 10 -> 11 -> NULL

不幸的是它失败了,因为

(newnode->get_next_ptr())->set_prev_ptr(newnode);

尝试

11 -> NULL -> 11;

所以

if (newnode->get_next_ptr() != NULL)

需要保护它。

此外,重新思考

lastnode = cursor;

自从cursor以来明确newnode cursor的下一个点不是最后一个节点。根据{{​​1}}点的位置,cursor可能不是最后一个节点。

建议:

提供那些开放的next和prev访问器会导致newnode的封装失败,因为任何人都可以使用访问器执行他们想要的任何操作node。您也可以声明成员变量node并节省时间。

这似乎是public成为List friend或节点全部{{​​1}}访问权限(或node)的好例子并且远离窥探眼睛封装在public内。无论哪种方式,都会失去访问者。