尝试从链接列表中删除节点的分段错误错误

时间:2019-01-09 04:51:07

标签: c++

我正在尝试创建一种方法(delete_at),该方法删除给定位置的节点,但出现分段错误(堆芯丢失)错误。奇怪的是,代码可以正常工作并有效地删除了我想要的节点,但是我不断收到该错误。错误出现在delete_at中,其他方法也可以正常工作。

有人可以帮助我吗?

#include <iostream>
#include <stdlib.h>
using namespace std;

//each of the nodes of our list is a class
template <class T> class node {

    private:

        T data;

    public:

        node <T> *next;

        node(): data(NULL), next(NULL) {}
        node(T x): data(x), next(NULL) {}

        T get_data () {

            return (data);
        }
};

template <class T> class list {

    private:

        node <T> *head, *p, *last;

    public:

        list(): head(NULL), p(NULL), last(NULL) {}

        ~list () {

            node <T> *n;
            for (p = head; p != NULL; p = p->next) {

                n = p->next;
                delete (p);
                p = n;
            }
            delete (n);
            cout << "list destroyed." << endl;
        }

        bool is_empty () {

            return (head == NULL);
        }

        //inserts a node at the beginning of the list
        void append (T x) {

            p = new node <T> (x);

            if (head == NULL) {

                head = p;
                last = head;
            }
            else {

                p->next = head;
                head = p;
            }
        }

        //inserts a node at the end of the list
        void push (T x) {

            p = new node <T> (x);

            if (head == NULL) {

                head = p;
                last = head;
            }
            else {

                last->next = p;
                last = p;
            }
        }

        void pop () {

            if (is_empty())
                cout << "empty list.";
            else if (head == last)
                head = last = NULL;
            else {

                for (p = head; p->next != last; p = p->next);
                delete (last);
                last = p;
                last->next = NULL;
            }
        }

        void delete_at (int i) {

            if (is_empty())
                cout << "empty list.";
            else if (i < size()) {

                p = head;

                if (i == 0) {

                    head = p->next;
                    delete (p);
                }
                else {

                    for (int j=0; j < i-1; j++)
                        p = p->next;

                    node <T> *tmp = p->next;
                    if (tmp->next != NULL) {

                        p->next = tmp->next;

                    }
                    else {
                        last = p;
                        last->next = NULL;
                    }

                    delete (tmp);
                }
            }
            else
                cout << "Invalid index." << endl;
        }

        void print () {

            for (p = head; p != NULL; p = p->next)
                cout << p->get_data() << " ";

            cout << endl;
        }

        int size () {

            int size = 0;
            for (p = head; p != NULL; size++, p = p->next);
            return (size);
        }

        T operator [] (int index) {

            int i;
            for (i=0, p = head; i < index; p = p->next, i++);
            return (p->get_data());
        }
};

int main () {

    //initializing random seed
    srand (time(NULL));

    list <int> l;

    cout << "Is the list empty? " << l.is_empty() << endl;
    l.push(rand() % 100);
    l.push(rand() % 100);
    l.push(rand() % 100);
    l.append(rand() % 100);
    l.push (rand() % 100);
    cout << "Is the list still empty? " << l.is_empty() << endl;
    cout << "l[2] = " << l[2] << endl << endl;
    cout << "size of the list: " << l.size() << endl;
    l.print ();

    l.pop ();
    l.print();

    l.delete_at (0);
    l.print ();
    l.delete_at (10);

    return (0);
}

1 个答案:

答案 0 :(得分:0)

您的代码中有许多错误。一次做一小步,并进行很多测试。

以下是一些问题和建议:

  • 如果列表为空并且调用了析构函数,则将删除未初始化的n。
  • 在析构函数中,每个循环迭代前进两次(一次在for语句中一次,一次在循环块中),但仅删除一项。因此,只有大约一半的项目被正确删除。
  • 如果解决以上2个问题,则循环后无需删除n。
  • 您的变量应在首次使用时进行初始化。
  • 在您的delete_at函数中,先询问大小并没有多大意义,因为它会使列表重复两次。特别地,如果i为0,则长度没有太大用处。
  • 如果您调用delete_at(0)以获得包含单个项目的列表,则您的代码将无法正确更新last,也不会将head重置为nullptr
  • li>
  • 将指针prev初始化为nullptr并前进直到达到所需的索引可能会容易得多。到那时,您知道是否必须更新头部(prev仍然为零)和/或尾部(next为零,以便删除该项目)。
  • 如评论中所述,p不应是成员变量。
  • pop中,如果列表包含单个项目,则不会删除该项目。
  • 鉴于内部状态可能不正确(例如last未更新),很难在接下来的几步中预测是否出了问题。
  • 您应该删除复制并移动节点类的构造函数ans分配(并列出),以确保不会意外调用它们。
  • 您的默认构造函数不初始化数据。由于未使用它,您可以考虑删除它。

由于delete_at中有2个main呼叫点,因此您的问题也无法说明何时发生错误。并且提供您获得的输出将很有用。

我认为没有必要添加5个项目来获取崩溃,因此删除一些“更新”以查看崩溃是否仍会发生,可以更快地推断出实际状态。

我建议您进行一些单元测试。您应该在构造函数/析构函数中添加一个对象计数器或输出调用,以帮助检测缺失的删除。

要进行测试,您可以执行以下操作:

  • 创建并销毁一个空列表。
  • 创建,推送项目,销毁列表
  • 创建,推送项目,弹出项目,销毁列表
  • 创建,推送项目,删除索引为0的项目,销毁列表
  • 通过添加项目而不是推送项目来进行重复。
  • 创建一个空列表,然后在其上调用pop,delete_at...。
  • 添加多个项目并删除部分或全部项目。

对于测试,您可以简单地使用data的特定值进行测试,并检查您是否在某些时候具有预期的项目(并且您已经正确删除了适当数量的节点)。