【问题标题】:Doubly linked list not taking input after calling a delete function调用删除函数后双向链表不接受输入
【发布时间】:2021-11-20 00:14:43
【问题描述】:

问候堆栈溢出。我的程序应该采用用户输入的字符行并将它们附加到列表中。如果在输入中读取主题标签,该程序还应该删除最近附加的字符。

我的程序大部分都可以运行,但是当我尝试通过添加太多主题标签来破坏它时遇到了错误。执行此操作后,如果使用了太多主题标签,则列表停止接受附加内容将不显示任何内容。

我希望我只包含我认为有用的代码,如果不需要 main 函数,请见谅。

#include <iostream>
using namespace std;


class doubleList
{
    public:
        doubleList() { first = NULL; } // constructor

        void append(char); // adds entry to the end of the list
        void remove_last(); // removes the last item from a list

        friend ostream& operator<<(ostream& out, const doubleList& l); // outputs in forward order

    private:
        struct Node
        {
            char data;
            Node *next;
            Node *prev;
        };
        Node *first;
        Node *last;  
};

void doubleList::append(char entry)
{
    Node* temp = new Node();
    temp -> data = entry;
    temp -> next = NULL;

    if (first == NULL)
    {
        first = temp;
        last = temp;
    }
    else
    {
        last -> next = temp;
        temp -> prev = last;
        last = temp;
    }
}

void doubleList::remove_last()
{
    if (first -> next == NULL)
    {
        delete first;
    }
    else if (first != NULL)
    {
        last = last -> prev;
        delete last -> next;
        last -> next = NULL;
    }
}

ostream& operator<<(ostream& out, const doubleList& l)
{
    doubleList::Node* q;
    q = l.first;

    while (q != NULL)
    {
        out << q -> data;
        q = q -> next;
    }
    return out;
}

int main()
{
    doubleList list;
    char ch[100];

    cout << "Enter a line of characters; # will delete the most recent character." << endl;
        for (int i = 0; i < 100; i++)
        {
            cin.get(ch[i]);
            list.append(ch[i]);

            if (ch[i] == '#')
            {
                list.remove_last();
                list.remove_last(); // called twice becaue it removes the hashtag from the list
            }                       // and i was too lazy to make it so it doesnt do that so this
                                    // is simply an easier fix
            if (ch[i] == '\n')      // exits the loop when enter is clicked
                break;
        }

    cout << list;

    return 0;
}

我的程序成功运行如下所示:

Enter a line of characters; # will delete the most recent character.

abcd##fg

abfg

添加过多标签时我的程序:

Enter a line of characters; # will delete the most recent character.

ab#####efgh

在用户输入后没有显示任何内容。提前致谢。

【问题讨论】:

  • 请发帖minimal reproducible example。什么是附加()?您还缺少包含 to 以便编译。
  • 如前所述,我已经删除了很多代码,只显示了我认为有问题的功能。主函数中列出的附加函数会将数据添加到列表的末尾。很抱歉忘记了那个。这能澄清什么吗?
  • 注意:first -&gt; next 更常见(总是?)写成first-&gt;next
  • 使用更新的代码和输入 `ab#####efgh` t 在 doubleList::append() 上的 operator new(unsigned long) 上为我崩溃。这是一个完全不同的问题。
  • minimal reproducible example 的提示: 不要依赖用户输入。您有导致崩溃的示例输入,因此只需假设这是输入。 (不过,更短的输入会更好。根据问题描述,我猜a##d 的输入足以重现问题。)也就是说,您的主要功能可以减少到int main() { doubleList list; list.append('a'); list.append('#'); list.remove_last(); list.remove_last(); list.append('#'); list.remove_last(); list.remove_last(); list.append('d'); cout &lt;&lt; list; }。保持简单,忽略您的最终功能,并专注于错误。

标签: c++ class linked-list doubly-linked-list function-definition


【解决方案1】:

您还应该在构造函数中将指针last 设置为nullptr

doubleList() { first = nullptr; last = nullptr; }

函数append 不正确,因为它没有设置附加到列表的第一个节点的数据成员prev。应该写成

void doubleList::append(char entry)
{
    Node* temp = new Node();
    temp -> data = entry;
    temp -> next = nullptr;
    temp -> prev = last; 

    if (first == NULL)
    {
        first = temp;
    }
    else
    {
        last -> next = temp;
    }

    last = temp;
}

函数removeList 可以调用未定义的行为,因为在函数的最开始它不检查指针first 是否等于nullptr。并且在删除指针first 指向的节点后,它不会将指针firstlast 设置为nullptr。该函数可以通过以下方式定义。

void doubleList::remove_last()
{
    if ( last )
    {
        Node *tmp = last;

        last = last->prev;

        if ( last != nullptr )
        {
            last->next = nullptr;
        }
        else
        {
            first = nullptr;
        }

        delete temp;
    }
}

【讨论】:

  • 谢谢你的回答,看来我很接近了,只是不完全在那里。我认为 nullptr 比 NULL 使用更广泛,所以我将从现在开始使用它。
  • @user486543 nullptr 是一个nullptr_t,它允许编译器类型检查(更好的类型安全性)和消歧。使用它应该会导致更少的错误、更好的诊断和更少的模板争吵。即使它的使用量没有增长,我也会推荐使用它(我会疑惑为什么人们没有更快地接受它)。
【解决方案2】:

remove_last() 中释放时,您首先依赖为NULL,但不要在free 之后设置它。由于您的代码不完整,我不知道last 是什么,以及为什么您的逻辑不依赖于remove_last() 而不是first

类似的东西(未经测试);

void doubleList::remove_last() {
    if(!last) return;

    if(last == first) {
       free last;
       first = nullptr;
       last = nullptr;
       return;
    }
  
    last = last->prev;
    free last->next;
    last->next = nullptr;
}

【讨论】:

  • 您想查看我的全部代码吗?它不到一百行,但我不想全部粘贴,因为如果我展示我的整个代码,我会感到羞耻。
  • 不,我希望你发布 minimal 工作代码。
  • 现在的代码是不是看起来更够用了?
  • 您尚未添加标头包含,因此尚未使用命名空间进行编译。 IE。在你要求我们之前尝试编译你的东西。
猜你喜欢
  • 1970-01-01
  • 2016-06-11
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-06
  • 1970-01-01
  • 2019-07-23
  • 2020-12-18
相关资源
最近更新 更多