Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 尝试从链接列表中删除节点时出现分段错误_C++ - Fatal编程技术网

C++ 尝试从链接列表中删除节点时出现分段错误

C++ 尝试从链接列表中删除节点时出现分段错误,c++,C++,我正在尝试创建一个方法(delete\u at)来删除给定位置的节点,但是我得到了一个分段错误(核心转储)错误。奇怪的是,代码工作正常,有效地删除了我想要的节点,但我一直收到错误。错误在处的delete\u中,其他方法工作正常 有人能帮我吗 #include <iostream> #include <stdlib.h> using namespace std; //each of the nodes of our list is a class template <

我正在尝试创建一个方法(
delete\u at
)来删除给定位置的节点,但是我得到了一个分段错误(核心转储)错误。奇怪的是,代码工作正常,有效地删除了我想要的节点,但我一直收到错误。错误在处的
delete\u中,其他方法工作正常

有人能帮我吗

#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);
}
#包括
#包括
使用名称空间std;
//列表中的每个节点都是一个类
模板类节点{
私人:
T数据;
公众:
节点*下一步;
node():数据(NULL),下一个(NULL){}
节点(tx):数据(x),下一个(NULL){
无法获取_数据(){
返回(数据);
}
};
模板类列表{
私人:
节点*head,*p,*last;
公众:
list():head(NULL)、p(NULL)、last(NULL){}
~list(){
节点*n;
for(p=head;p!=NULL;p=p->next){
n=p->next;
删除(p);
p=n;
}
删除(n);
cout-next=p;
last=p;
}
}
void pop(){
如果(是空的())
cout next!=last;p=p->next);
删除(最后一次);
last=p;
last->next=NULL;
}
}
在(int i)处作废删除_{
如果(是空的())
下一步;
删除(p);
}
否则{
对于(int j=0;jnext;
节点*tmp=p->next;
如果(tmp->next!=NULL){
p->next=tmp->next;
}
否则{
last=p;
last->next=NULL;
}
删除(tmp);
}
}
其他的
无法获取_数据());
}
};
int main(){
//初始化随机种子
srand(时间(空));
清单l;

你的代码中有很多错误。一次只做一小步,然后进行大量测试

以下是一些问题和建议:

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

我认为没有必要添加5项来获得崩溃,因此删除一些“更新”以查看崩溃是否仍然发生,这将加快对实际状态的推理

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

对于您的测试,您可以执行以下操作:

  • 创建并销毁空列表
  • 创建、推送项目、销毁列表
  • 创建、推送项目、弹出项目、销毁列表
  • 创建、推送项目、删除索引0处的项目、销毁列表
  • 通过追加项目而不是推送项目重复此操作
  • 创建一个空列表并调用pop,删除其上的\u
  • 添加多个项目并删除部分或所有项目

对于您的测试,您只需使用
数据的特定值进行测试
,并检查您在某个点上是否具有预期的项(以及是否已正确删除适当数量的节点).

学习使用调试器。它将直接指向错误发生的位置。析构函数是错误的。它跳过节点,并可能由于取消引用空指针而导致未定义的行为。另一个提示--在测试类时不要使用随机数据。原因是,如果类不工作,使用随机数据只会导致错误更难。只要先使用已知值——一旦你的类开始工作,你就可以使用随机数据。
p
不应该是该类的成员。它只在成员函数的循环中使用,实际上并不存储该类的任何数据,所以当你真的需要它时,就在循环中声明它。你应该使用
nullptr
而不是<代码>空值