在双重链表删除函数中出现Seg错误

C++: Seg fault in doubly linked list remove function

本文关键字:Seg 错误 函数 链表 删除      更新时间:2023-10-16

这个双链表的移除函数存在分割错误。在linux终端中使用gdb调试显示
1)只有第一个条件if(curr->prev == NULL),要删除的节点是到达列表中的第一个节点。
2)在delete curr命令下,程序进入对数据对象建模的类的析构函数,在delete title命令下中断。

编辑:

在实现user6545984答案后,唯一的问题是else if(curr->next == NULL)条件下tail = tail->prev上的分割错误。程序无法通过此条件语句。
另外,下面还添加了其他代码。很抱歉这么长。

add和remove函数的代码,以及析构函数的代码:

添加函数(创建双链表)

 void SongList::addSongSorted(const Song &aSong)
    {
        char title[MAX_CHAR];
        char currTitle[MAX_CHAR];
        aSong.getTitle(title);
        Node * newNode = new Node(aSong);
        Node * prev = NULL;
        Node * curr = head;
        while(curr)
        {
            curr->song.getTitle(currTitle);
            if(strcmp(title, currTitle) < 0)
                break;
            prev = curr;
            curr = curr->next;
        }
        newNode->next = curr;
        newNode->prev = prev;     //Added due to answer. See edit note.
        if(!prev)
            head = newNode;
        else
        {
            prev->next = newNode;
        }
        size++;
    }

删除功能
void SongList::remove(const Song& aSong)
{
    Node *curr = head;
    int indexRem = 0;
    int j = 0;
    //get the index to remove
    cout << "Enter the index to remove.n";
    cout << "This value can be obtained via the list all   functionality.n";
    cin >> indexRem;
    while(indexRem > getSize()|| indexRem < 0)
    {
        cout << "Enter a valid index to remove.n";
        cin >> indexRem;
    }
    while(curr && j < indexRem)
    {
        curr=curr->next;
        j++;
    }
    if(!curr)
    {
        cout << "didnt find anything" << endl;
    }
    else
    {
       if(curr->prev == NULL)      //NOTE: this is the only condition ever engaged
       {
        head = head->next;
        head->prev = NULL;
        delete curr;            //NOTE: goes to destructor
        curr = NULL;
        }
        else if(curr->next == NULL)
        {
            tail = tail->prev;      //EDIT: only issue is seg fault here
            tail->next = NULL;
            delete curr;
            curr = NULL;
        }
        else
        {
            Node * previous = curr->prev;
            Node * following = curr->next;
            previous->next = following;
            following->prev = previous;
            delete curr;
        }
    }

析构函数(现在请忽略)

    Song::~Song()
        {
            if(title != NULL)
                delete [] title;    //Breaks here
            if(artist != NULL)
                delete [] artist;
            if(album != NULL)
                delete [] album;
        }

对象类

头文件
#ifndef SONG_H
#define SONG_H
#include<cstring>
#include<stdio.h>
#include<cstdlib>
const int MAX_CHAR = 101;
const int SONG_CAPACITY = 100;
class Song
{
public:
    //constructors
    Song();
    Song(const char title[], const char artist[], const char album[], int min, int sec);
    //Destructor
    ~Song();
    //accessor functions
    void getTitle(char title[]) const;
    void getArtist(char artist[]) const;
    void getAlbum(char album[]) const;
    int getMin()const;
    int getSec()const;
    void print() const;
    //mutator functions
    void setTitle(const char title[]);
    void setArtist(const char artist[]);
    void setAlbum(const char album[]);
    void setMin(int &min);
    void setSec(int &sec);

private:
    char*    title;
    char*    artist;
    char*    album;
    int     min;
    int     sec;
};

#endif

对象类

源文件
    #include "song.h"
    #include <iostream>
    using namespace std;

    Song::Song()
    {
        title = new char[strlen("no title")+1];
        strcpy(title, "no title");
        artist = new char[strlen("no artist")+1];
        strcpy(artist, "no artist");
        album = new char[strlen("no album")+1];
        strcpy(album, "no album");
        min = 0;
        sec = 0;
    }

    Song::Song(const char title[], const char artist[], const char album[], int min, int sec)
    {
        this->title = new char[strlen(title)+1];
        strcpy(this->title, title);
        this->artist = new char[strlen(artist)+1];
        strcpy(this->artist, artist);
        this->album = new char[strlen(album)+1];
        strcpy(this->album, album);
        this->min = min;
        this->sec = sec;
    }
    Song::~Song()
    {
        if(title != NULL)
            delete [] title;
        if(artist != NULL)
            delete [] artist;
        if(album != NULL)
            delete [] album;
    }
    void Song::getTitle(char title[]) const
    {
        strcpy(title, this->title);
    }
    void Song::getArtist(char artist[]) const
    {
        strcpy(artist, this->artist);
    }
    void Song::getAlbum(char album[]) const
    {
        strcpy(album, this->album);
    }
    int Song::getMin()const
    {
        return min;
    }
    int Song::getSec()const
    {
        return sec;
    }

    void Song::print() const
    {
       cout << title << 't'
            << artist << 't'
            << album << 't'
            << min << 't'
            << sec << endl;
    }
    void Song::setTitle(const char title[])
    {
        if(this->title != NULL)
            delete [] this->title;
        this->title = new char[strlen(title)+1];
        strcpy(this->title, title);
    }
    void Song::setArtist(const char artist[])
    {
        if(this->artist != NULL)
            delete [] this->artist;
        this->artist = new char[strlen(artist)+1];
        strcpy(this->artist, artist);
    }
    void Song::setAlbum(const char album[])
    {
        if(this->album != NULL)
            delete [] this->album;
        this->album = new char[strlen(album)+1];
        strcpy(this->album, album);
    }
    void Song::setMin(int &min)
    {
        this->min = min;
    }
    void Song::setSec(int &sec)
    {
        this->sec = sec;
    }
###Header file for object management class
    #ifndef SONG_LIST
    #define SONG_LIST
    #include "song.h"
    #include <iostream>
    using namespace std;
    class SongList
    {
    public:
        SongList();
        SongList(const char fileName[]);
        ~SongList();
        bool get(int index, Song& aSong) const;
        //Search function declaration
        void searchArtist(const char artist[], Song& match) const;
        void searchAlbum(const char album[], Song& match) const;
        int getSize() const;
        void printAll() const;
        void saveToFile(const char fileName[]) const;
        void addSong(const Song& aSong);
       // void addAtStart(const Song& aSong);
       // void append(const Song& aSong);
        void addSongSorted(const Song& aSong);
        void loadFromFile(const char fileName[]);
        void remove(const Song& aSong);
    private: 
        struct Node
        {
            Song    song;
            Node *  next;
            Node *  prev;
            Node(const Song& aSong)
            {
                char    title[MAX_CHAR];
                char    artist[MAX_CHAR];
                char    album[MAX_CHAR];
                int     min;
                int     sec;
                aSong.getTitle(title);
                aSong.getArtist(artist);
                aSong.getAlbum(album);
                min =  aSong.getMin();
                sec =  aSong.getSec();
                song.setTitle(title);
                song.setArtist(artist);
                song.setAlbum(album);
                song.setMin(min);
                song.setSec(sec);
                next = NULL;
            }
        };
        Node * head;
        Node * tail;
        int size;
    };
    #endif
###Source file for object management class
#include "songlist.h"
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstring>
using namespace std;
//Ok as is
SongList::SongList()
{
    head = NULL; 
    tail = NULL;   
    size = 0;
}
//OK as is
SongList::SongList(const char fileName[])
{
    head = NULL;
    tail = NULL;
    size = 0;
    loadFromFile(fileName);
}
//Needs modification to deconstruct tail...
SongList::~SongList()
{
    Node * curr = head;
    while(head != NULL)
    {
        curr = head->next;
        delete head;
        head = curr;
    }
}
//OK as is
void SongList::loadFromFile(const char fileName[])
{
    ifstream        in;
    char            title[MAX_CHAR];
    char            artist[MAX_CHAR];
    char            album[MAX_CHAR];
    int             min;
    int             sec;
    Song    aSong;
    in.open (fileName);
    if(!in)
    {
        in.clear();
        cerr << endl << "Fail to open " 
        << fileName << " for input!" << endl << endl;
        exit(1);
    }
    //cout << "loading point reached" << endl;
    in.getline(title, MAX_CHAR, ';');
    while (!in.eof())
    {
        //cout << "check input from file" << endl;
        in.getline(artist, MAX_CHAR, ';');
        in.getline(album, MAX_CHAR, ';');
        in >> min;
        in.ignore(MAX_CHAR, ';');
        in >> sec;
        in.ignore(MAX_CHAR, 'n');
        aSong.setTitle(title);
        aSong.setArtist(artist);
        aSong.setAlbum(album);
        aSong.setMin(min);
        aSong.setSec(sec);
        addSong(aSong);
     // aSong.print();
        in.getline(title, MAX_CHAR, ';');
    }
    in.close();
}
//Ok as is
int SongList::getSize()const
{
    return size;
}
bool SongList::get(int index, Song &aSong) const
{
    char    title[MAX_CHAR];
    char    artist[MAX_CHAR];
    char    album[MAX_CHAR];
    int     min;
    int     sec;
    if(index < 0 || index >= size)
        return false;
    int i;
    Node * curr = head;
    for(i = 0; i < index; i++)
    {
        curr = curr->next;
    }
    curr->song.getTitle(title);
    curr->song.getArtist(artist);
    curr->song.getAlbum(album);
    curr->song.getMin();
    curr->song.getSec();
    aSong.setTitle(title);
    aSong.setArtist(artist);
    aSong.setAlbum(album);
    aSong.setMin(min);
    aSong.setSec(sec);
    return true;
}
//OK as is 
void SongList::searchArtist(const char artist[], Song& match) const
{
    Node * curr;
    char    currentTitle[MAX_CHAR];
    char    currentArtist[MAX_CHAR];
    char    currentAlbum[MAX_CHAR];
    int     currentMin;
    int     currentSec;
    for(curr = head; curr != NULL; curr = curr->next)
    {
        curr->song.getTitle(currentTitle);
        curr->song.getArtist(currentArtist);
        curr->song.getAlbum(currentAlbum);
        curr->song.getMin();
        curr->song.getSec();
        if(strcmp(artist, currentArtist) == 0)
        {
            cout << "Found: " << currentTitle << 't' 
                              << currentArtist << 't'
                              << currentAlbum << 't'
                              << currentMin << ':' 
                              << currentSec << endl;
        }
    }
}
//Ok as is
void SongList::searchAlbum(const char album[], Song &match) const
{
    Node * curr;
    char    currentTitle[MAX_CHAR];
    char    currentArtist[MAX_CHAR];
    char    currentAlbum[MAX_CHAR];
    int     currentMin;
    int     currentSec;
    for(curr = head; curr != NULL; curr = curr->next)
    {
        curr->song.getTitle(currentTitle);
        curr->song.getArtist(currentArtist);
        curr->song.getAlbum(currentAlbum);
        curr->song.getMin();
        curr->song.getSec();
        if(strcmp(album, currentAlbum) == 0)
        {
            cout << "Found: " << currentTitle << 't'
                              << currentArtist << 't'
                              << currentAlbum << 't'
                              << currentMin << ':'
                              << currentSec << endl;
        }
    }
}
//OK as is 
void SongList::printAll() const
{
    Node * curr;
    char    title[MAX_CHAR];
    char    artist[MAX_CHAR];
    char    album[MAX_CHAR];
    int     min;
    int     sec;
    int     index = 0;
    for(curr = head; curr != NULL; curr = curr->next)
    {
        curr->song.getTitle(title);
        curr->song.getArtist(artist);
        curr->song.getAlbum(album);
        min = curr->song.getMin();
        sec = curr->song.getSec();
        cout << index << " " << title << " "  
             << artist << " " << album << " " 
             << min << ':' << sec << endl;
        index++;
    }
}
//OK as is 
void SongList::saveToFile(const char fileName[])const
{
    ofstream    out;
    Node*       curr;
    char        title[MAX_CHAR];
    char        artist[MAX_CHAR];
    char        album[MAX_CHAR];
    int         min = 0;
    int         sec = 0;
    out.open(fileName);
    if(!out)
    {
        out.clear();
        cerr << endl << "Fail to open" << fileName << ". Check your directory." << endl << endl;
        exit(1);
    }
    for(curr = head; curr; curr = curr->next)
    {
        curr->song.getTitle(title);
        curr->song.getArtist(artist);
        curr->song.getAlbum(album);
        min = curr->song.getMin();
        sec = curr->song.getSec();
        out << title << ';' << artist << ';' << album << ';' << min << ';' << sec << endl;
    }
    out.close();
}
void SongList::addSong(const Song &aSong)
{
    addSongSorted(aSong);
}   
//Don't think I need this
/*
void SongList::addAtStart(const Song &aSong)
{
    Node * newNode = new Node(aSong);
    newNode->next = head;
    head = newNode;
    size++;
}
//...or this
void SongList::append(const Song &aSong)
{
    Node * newNode = new Node(aSong);
    if(!head)
        head = newNode;
    else
    {
        Node * curr = head;
        while(curr->next)
        {
            curr = curr->next;
        }
        curr->next = newNode;
    }
    size++;
}
*/
void SongList::addSongSorted(const Song &aSong)
{
    char title[MAX_CHAR];
    char currTitle[MAX_CHAR];
    aSong.getTitle(title);
    Node * newNode = new Node(aSong);
    Node * prev = NULL;
    Node * curr = head;
    while(curr)
    {
        curr->song.getTitle(currTitle);
        if(strcmp(title, currTitle) < 0)
            break;

        prev = curr;
        curr = curr->next;
    }
    newNode->next = curr;
    newNode->prev = prev;
    if(!prev)
        head = newNode;
    else
    {
        prev->next = newNode;
    }
   // printAll();
    size++;
}

void SongList::remove(const Song& aSong)
{
    Node *curr = head;
    int indexRem = 0;
    int j = 0;
    cout << "Enter the index to remove.n";
    cout << "This value can be obtained via the list all functionality.n";
    cin >> indexRem;
    while(indexRem > getSize()|| indexRem < 0)
    {
        cout << "Enter a valid index to remove.n";
        cin >> indexRem;
    }
    while(curr && j < indexRem)
    {
        curr=curr->next;
        j++;
    }
    if(!curr)
    {
        cout << "didnt find anything" << endl;
    }
    else 
    {
       if(curr->prev == NULL)
       { 
        head = head->next;
        head->prev = NULL;
        delete curr;
        curr = NULL;
        }
        else if(curr->next == NULL)
        {
            tail = tail->prev;
            tail->next = NULL;
            delete curr;
            curr = NULL;
        }
        else
        {
            Node * previous = curr->prev;
            Node * following = curr->next;
            previous->next = following;
            following->prev = previous;
            delete curr;
        }
    }
    size--;
}

有什么建议吗?

您在添加新节点时忘记了->prev指针,这使得if(curr->prev == NULL)始终为true。只需在addSongSorted()函数中添加newNode->prev = prev;

顺便说一下,在删除节点时可能需要--size

这会给你一个错误,因为你不应该使用new或new[]而使用delete或delete[]。New在运行时从堆中获得一些内存,而char[size]在编译时提供一些内存,因此变量的大小在代码中是硬编码的