对链表的操作完成后出现错误



我已经为它编写了一个链表类和一些方法。它很好地完成了所有方法,但之后程序输出了一个错误。为什么会发生这种情况?

节点hpp:

class Node{
public:
int data;
Node * next;
Node(int val);
};

节点cpp:

#include <stdio.h>
#include "node.hpp"
Node::Node(int val)
: next(NULL)
{
data = val;
}

链接列表类别hpp:

#include "node.cpp"
class LL {
private:
Node *head;
Node *tail;
public:
LL();
~LL();

int LL_append(int value);
void LL_print();
int LL_search(int target);
int LL_catenate(LL * list);
int LL_insert(int x);

};

链接列表类cpp:

#include "LL.hpp"
#include <stdio.h>
#include <iostream>
using std::cout;
LL::LL()
:
head(NULL),
tail(NULL)
{
}
LL::~LL(){
Node * curr = head;
while(head != NULL){
if(head == tail){
delete head;
return;
}
while(curr->next != tail){
curr = curr->next;
}
delete tail;
tail = curr;
curr = head;
}
}
//returns 1 for success and 0 for fail
int LL::LL_append(int value){
int ret = 0;
Node * newNode = new Node(value);
if(value != NULL){
if(head == NULL){
head = newNode;
tail = newNode;
}   
else{
tail->next = newNode;
tail = newNode;
}
ret = 1;
}
return ret;
}
//prints out list
void LL::LL_print(){
Node * curr = head;
cout << "[ ";
while(curr != NULL){
cout << curr->data << " ";
curr = curr->next;
}
cout << "]n";
}
//returns the number of times it appears in the list. return -1 if failed
int LL::LL_search(int target){
int count = 0;
Node * curr = head;
while(curr != NULL){
if(curr->data == target){
count++;
}
curr = curr->next;
}
return count;
}
//returns 1 on success
int LL::LL_catenate(LL * list){
if(list->head == NULL){
}
else if(head == NULL){
head = list->head;
tail = list->tail;
}
else{
tail->next = list->head;
tail = list->tail;
}
return 1;
}
int LL::LL_insert(int x){
int ret = 0;
Node * curr = head;
Node * newNode = new Node(x);
if(head == NULL){
head = newNode;
tail = newNode;
ret = 1;
}
else if(head->data >= x){
printf("heren");
newNode->next = head;
head = newNode;
}
else{
Node * curr = head;
while( curr->next != NULL && curr->next->data < x){
curr = curr->next;
}
newNode->next = curr->next;
curr->next = newNode;
if(curr->next == NULL){
tail = newNode;
}
ret = 1;

}
return ret;
}

这就是我用来测试的方法:

int main(){
LL L1 = LL();
L1.LL_append(1);
L1.LL_append(3);
L1.LL_print();
printf("%dn", L1.LL_search(12));
printf("%dn", L1.LL_search(1));
LL L2 = LL();
L2.LL_append(5);
L2.LL_append(9);
L1.LL_catenate(&L2);
L1.LL_print();
L1.LL_insert(7);
L1.LL_print();
L1.~LL();
L2.~LL();
printf("donen");
}

这是程序的输出:

[ 1 3 ]
0
1
[ 1 3 5 9 ]
[ 1 3 5 7 9 ]
done
double free or corruption (fasttop)
Aborted (core dumped)

我从未见过在测试程序运行完成后发生错误。发生这种情况有什么原因吗?我相信这与插入方法有关。

  1. 除非显式构造对象(即使用placement new(,否则不应调用析构函数
  2. 如果定义了析构函数,还应该定义复制构造函数和复制赋值运算符。这被称为3规则

奖金-

  1. 您的程序效率极低。您从开始到结束对LinkedList进行迭代,以删除单个对象。考虑这种改进:
LL::~LL(){
Node* curr = head;
while(head != NULL){
head = curr->next;
delete curr;
curr = head;
}
}
  1. 您检查插入中的value != NULL。这只是检查value != 0,但它具有误导性,我看不出进行此检查的任何原因。如果你是认真的,写value != 0。否则-删除
不要手动调用析构函数。当链表超出作用域时,将自动调用析构函数。如果您只是删除对析构函数的显式调用,它就能正常工作。

请注意,您会收到有关使用NULL的警告。改为使用nullptr来修复此问题。

显式调用析构函数意味着它们会运行两次,一次是在调用它们时,另一次是当列表被销毁时。只需删除不需要的对析构函数的调用。

你的析构函数本身似乎不必要地复杂,可能只是:

LL::~LL(){
while(head){
Node* next = head->next;
delete head;
head = next;
}
tail = nullptr;
}

这还没有给你带来问题,但很可能很快就会出现,因为你有一个析构函数,你需要遵循三条规则,删除/定义复制构造函数和赋值运算符。

最新更新