C++:双向链表删除函数中的段错误

标签 c++ linked-list doubly-linked-list

此双向链表的删除函数中存在段错误。在linux终端用gdb调试显示
1) 只有第一个条件,if(curr->prev == NULL),其中要删除的节点是列表中的第一个节点。
2) 在命令 delete curr 上,程序进入模拟数据对象的类的析构函数,并在命令 delete title 上中断。

编辑:

实现 user6545984 答案后,唯一的问题是 else if(curr->next == NULL) 条件中 tail = tail->prev 的段错误. 程序无法通过此条件语句。
此外,下面还添加了其他代码。对于长度,我深表歉意。

添加和删除函数的代码,以及析构函数的代码:

添加函数(创建双向链表)

 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) 始终为真。只需在函数 addSongSorted() 中添加 newNode->prev = prev;

顺便说一句,当删除一个节点时,你可能需要--size

关于C++:双向链表删除函数中的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38864587/

相关文章:

c++ - 我如何在二维字符 vector 中查找和替换字符? C++

c++ - 为包含 STL 类的链表结构释放内存

java - 双向链表中的递归方法

java - 如何允许自定义有序链接列表类中存在重复项?

c++ - boost 灵气期待

c++ - 自定义对元组 vector 进行排序

c - 将节点添加到链表中的随机位置

c - 将节点插入 Dllist

c - 具有多个父节点和子节点的链表

c++ - 在这种情况下如何决定堆栈、堆和 boost::pool 分配?