铭凡 发表于 2023-6-12 19:56:08

求助这个功能怎么实现呀!

我正在写一个图书管理系统(准确地说是: copy代码然后在屎山旁边拉一坨)

然后我考虑到每次要录入或者修改数据, 可能人家点进来之后就反悔了或者想回去查看以下数据, 这个时候就不能强制人家输入, 而是如果人家直接输入Return就回去

它的原代码如下
voidLibraryManager::Add_book(book **q)//增加图书信息
{
        char m;

        std::cout << "请按照如下顺序输入图书信息! " << std::endl;

        book *p;//定义book类指针
        p = new book;//申请存储空尾间

        std::cout << "本书登录号 本书书籍名称 本书作者姓名 本书分类号 本书出版单位 本书出版时间 本书书籍价格" << std::endl;

        std::cin >> *p;

        if (*q == NULL)//检查链表是否为空链表
        {
                p->next = NULL;
                *q = p;
        }//如果链表为空则把链表头指向p
        else
        {
                p->next = NULL;//p是倒数第二个节点,next指针中保存这尾节点的地址值,p指向尾节点
                (zbook)->next = p;//如果链表不为空则把链表尾指向p
        }

        zbook = p;
        std::cout << "添加成功,是否继续添加:是Y,否N:" << std::endl;
        std::cin.clear();
        std::cin.ignore(1024, '\n');
        std::cin >> m;

        while ((m != 'Y'&& m != 'y' && m != 'N' && m != 'n') || std::cin.good() == FALSE)
        {
                std::cout << "输入错误,请重新输入:" << std::endl;
                std::cin.clear();
                std::cin.ignore(1024, '\n');
                std::cin >> m;
        }

        if (m == 'Y' || m == 'y')
        {
                Add_book(&abook);
                exit(EXIT_SUCCESS);
        }
        else if (m == 'N' || m == 'n')
        {
                std::cout << "正在返回到菜单,请勿操作" << std::endl;
                Sleep(1500);//停滞1.5s再继续
                system("cls");//清屏
                Menu();
                exit(EXIT_SUCCESS);
        }
}

然后我改之后的如下
voidLibraryManager::Add_book(book **q)//增加图书信息
{
//以下代码加入了输入Return就返回的功能, 但是有bug(输入之后会直接跳到错误)
//我的想法是, 将用户输入的内容和"Return"对比, 如果一样就返回, 如果不一样就流给*p
//但是, 没办法直接将ifReturn的内容流给*p(也可能是我不会)
//然后我就想把第一个数据给赋值过去, 但是它会往后面串一个emm
/*
        char m;

        std::cout << "请按照如下顺序输入图书信息, 如要返回请输入\"Return!\" " << std::endl;

        book *p;//定义book类指针
        p = new book;//申请存储空尾间

        std::cout << "本书登录号 本书书籍名称 本书作者姓名 本书分类号 本书出版单位 本书出版时间 本书书籍价格" << std::endl;
       
        std::string ifReturn;

        std::getline(std::cin, ifReturn);

        if ((ifReturn.compare("Return")) == 0)
        {
                std::cout << "正在返回到菜单,请勿操作" << std::endl;
                Sleep(1500);//停滞1.5s再继续
                system("cls");//清屏
                Menu();
                exit(EXIT_SUCCESS);
        }
        else
        {
                std::stringstream ss(ifReturn);
                std::cin.rdbuf(ss.rdbuf());
        }
        std::cin >> *p;

        if (*q == NULL)//检查链表是否为空链表
        {
                p->next = NULL;
                *q = p;
        }//如果链表为空则把链表头指向p
        else
        {
                p->next = NULL;//p是倒数第二个节点,next指针中保存这尾节点的地址值,p指向尾节点
                (zbook)->next = p;//如果链表不为空则把链表尾指向p
        }

        zbook = p;
        std::cout << "添加成功,是否继续添加:是Y,否N:" << std::endl;
        std::cin.clear();
        std::cin.ignore(1024, '\n');
        std::cin >> m;

        while ((m != 'Y'&& m != 'y' && m != 'N' && m != 'n') || std::cin.good() == FALSE)
        {
                std::cout << "输入错误,请重新输入:" << std::endl;
                std::cin.clear();
                std::cin.ignore(1024, '\n');
                std::cin >> m;
        }

        if (m == 'Y' || m == 'y')
        {
                Add_book(&abook);
                exit(EXIT_SUCCESS);
        }
        else if(m == 'N' || m == 'n')
        {
                std::cout << "正在返回到菜单,请勿操作" << std::endl;
                Sleep(1500);//停滞1.5s再继续
                system("cls");//清屏
                Menu();
                exit(EXIT_SUCCESS);
        }
*/
}

运行的时候, 就会无限出现: 输入错误请重试!

另外,明明都已经用了cin.clear();还有cin.ignore(100, '\n');了,为啥缓冲区的错误还是存在呢?

isdkz 发表于 2023-6-12 22:19:02

在你的代码中,你尝试使用std::stringstream对象来接受用户输入,然后再将它的缓冲区设置为std::cin的缓冲区。虽然这样做确实可能在某些情况下起作用,但它可能并不适用于你的特定情况,因为这种方法可能会导致某些异常行为,如你所描述的。

另外,当你的代码中出现 "输入错误请重试!" 这样的提示时,你可以检查std::cin.good()的返回值。这是因为你使用了while循环来检查输入的合法性,但是std::cin.good()可能在遇到错误的输入时返回false 。这可能就是为什么你看到无限循环的原因。

关于你的问题,如果你想要实现的功能是如果用户输入 "Return",则程序返回,而不是继续,那么你可以在获取用户输入并转化为std::string后直接检查它是否等于 "Return",如果是则返回,否则继续程序。

我做了一些小修改,使用std::istringstream对象而不是修改std::cin的缓冲区,并假设book对象的输入运算符已经正确重载。

void LibraryManager::Add_book(book **q) {
    char m;
    std::cout << "请按照如下顺序输入图书信息, 如要返回请输入\"Return\"! " << std::endl;

    book *p;
    p = new book;

    std::cout << "本书登录号 本书书籍名称 本书作者姓名 本书分类号 本书出版单位 本书出版时间 本书书籍价格" << std::endl;
   
    std::string userInput;
    std::getline(std::cin, userInput);

    if (userInput == "Return") {
      std::cout << "正在返回到菜单,请勿操作" << std::endl;
      Sleep(1500);
      system("cls");
      Menu();
      exit(EXIT_SUCCESS);
    }
    else {
      std::istringstream iss(userInput);
      iss >> *p;

      if (*q == NULL) {
            p->next = NULL;
            *q = p;
      }
      else {
            p->next = NULL;
            (zbook)->next = p;
      }

      zbook = p;
      std::cout << "添加成功,是否继续添加:是Y,否N:" << std::endl;
      std::cin.clear();
      std::cin.ignore(1024, '\n');
      std::cin >> m;

      while ((m != 'Y' && m != 'y' && m != 'N' && m != 'n') || !std::cin) {
            std::cout << "输入错误,请重新输入:" << std::endl;
            std::cin.clear();
            std::cin.ignore(1024, '\n');
            std::cin >> m;
      }

      if (m == 'Y' || m == 'y') {
            Add_book(&abook);
            exit(EXIT_SUCCESS);
      }
      else if (m == 'N' || m == 'n') {
            std::cout << "正在返回到菜单,请勿操作" << std::endl;
            Sleep(1500);
            system("cls");
            Menu();
            exit(EXIT_SUCCESS);
      }
    }
}


注意: 你需要确保book对象的输入运算符已经正确重载,以支持从std::istringstream对象中读取数据。

铭凡 发表于 2023-6-12 23:11:45

本帖最后由 铭凡 于 2023-6-12 23:16 编辑

isdkz 发表于 2023-6-12 22:19
在你的代码中,你尝试使用std::stringstream对象来接受用户输入,然后再将它的缓冲区设置为std::cin...

还是不行
执行结果如下:
##########欢迎使用图书信息管理系统##########
#############输入1 增加图书信息#############
#############输入2 显示图书信息#############
#############输入3 删除图书信息#############
#############输入4 修改图书信息#############
#############输入5 查找图书信息#############
#############输入6 按照价格排序#############
#############输入7 保存&&退出###############
1
请按照如下顺序输入图书信息, 如要返回请输入"Return"!
本书登录号 本书书籍名称 本书作者姓名 本书分类号 本书出版单位 本书出版时间 本书书籍价格
添加成功,是否继续添加[是Y/否N]:
y
123 123 123 123 123 123 123
输入错误,请重新输入:
1 2 3 4 5 6 7
输入错误,请重新输入:

1 2 3 4 5 6 7
输入错误,请重新输入:


然后我调试程序的时候,
std::string userInput;
        std::getline(std::cin, userInput);

这两行应该停下来等用户输入的, 但是它直接走下去了, 所以我觉得这是第一次我啥也没输入就显示“添加成功,是否继续添加[是Y/否N]:”这句话的原因

然后我输入Y继续,不管我输入什么,它都说我输入错误, 请重试

isdkz 发表于 2023-6-12 23:15:23

铭凡 发表于 2023-6-12 23:11
还是不行
执行结果如下:

看起来问题可能在于你的book类对输入流的处理方式。这可能是因为你的operator>>实现不适用于从空白字符(例如空格)分隔的字符串流中读取。

为了解决这个问题,你需要确保你的book类可以正确地从std::istringstream对象中读取。如果你的book类的输入运算符已经适当地重载,那么你应该可以像这样处理它:

std::istringstream iss(userInput);
iss >> p->login_number >> p->book_name >> p->author_name >> p->classification_number >> p->publisher >> p->publish_date >> p->book_price;


注意,上面的代码假设你的book类有如下的数据成员: login_number ,book_name ,author_name ,classification_number ,publisher ,publish_date ,book_price 。你需要根据你的book类的实际情况进行调整。

如果你的book类的operator>>重载是正确的,那么你应该可以直接使用iss >> *p 。如果不行,你就需要检查你的operator>>实现,确保它能正确处理从空格分隔的字符串流中读取。

另外,你的while循环条件可能也需要修改。在std::cin发生错误(例如输入不是 'Y', 'y', 'N', 'n' 的字符)时,你需要清空缓冲区并忽略剩余的输入,然后再尝试读取。你可以尝试如下的循环:

do {
    std::cin >> m;
    if (m != 'Y' && m != 'y' && m != 'N' && m != 'n') {
      std::cout << "输入错误,请重新输入:" << std::endl;
      std::cin.clear();
      std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
} while (m != 'Y' && m != 'y' && m != 'N' && m != 'n');


在这个循环中,如果输入的不是 'Y', 'y', 'N', 'n' 中的一个,那么会清空输入流并忽略剩余的输入,然后提示用户重新输入。当输入正确时,循环才会结束。

铭凡 发表于 2023-6-12 23:29:45

isdkz 发表于 2023-6-12 23:15
看起来问题可能在于你的book类对输入流的处理方式。这可能是因为你的operator>>实现不适用于从空 ...

你好,按照你的思路,我改了一下,代码如下
char m;
        std::cout << "请按照如下顺序输入图书信息, 如要返回请输入\"Return\"! " << std::endl;

        book *p;
        p = new book;

        std::cout << "本书登录号 本书书籍名称 本书作者姓名 本书分类号 本书出版单位 本书出版时间 本书书籍价格" << std::endl;

        std::string userInput;
        std::getline(std::cin, userInput);

        if (userInput == "Return")
        {
                std::cout << "正在返回到菜单,请勿操作" << std::endl;
                Sleep(1500);
                system("cls");
                Menu();
                exit(EXIT_SUCCESS);
        }
        else
        {
                std::istringstream iss(userInput);
                iss >> p->book_Entry_number >> p->book_name >> p->author_name >> p->book_number >> p->publish_address >> p->publish_time >> p->book_price;

                if (*q == NULL)
                {
                        p->next = NULL;
                        *q = p;
                }
                else
                {
                        p->next = NULL;
                        (zbook)->next = p;
                }

                zbook = p;
                std::cout << "添加成功,是否继续添加[是Y/否N]: " << std::endl;
                std::cin.clear();
                std::cin.ignore(1024, '\n');

                do {
                        std::cin >> m;
                        if (m != 'Y' && m != 'y' && m != 'N' && m != 'n') {
                                std::cout << "输入错误,请重新输入:" << std::endl;
                                std::cin.clear();
                                //std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');//"std::numeric_limits<std::streamsize>::max()"说我max未定义
                                std::cin.ignore(1024, '\n');//我暂时还用这个
                        }
                } while (m != 'Y' && m != 'y' && m != 'N' && m != 'n');

                if (m == 'Y' || m == 'y')
                {
                        Add_book(&abook);
                        exit(EXIT_SUCCESS);
                }
                else if (m == 'N' || m == 'n')
                {
                        std::cout << "正在返回到菜单,请勿操作" << std::endl;
                        Sleep(1500);
                        system("cls");
                        Menu();
                        exit(EXIT_SUCCESS);
                }
        }

所以。。。现在就出现了新的问题:
1. 我现在根本没办法输入书籍信息, 因为
std::string userInput;
        std::getline(std::cin, userInput);
这两行执行之后,人家就自动以为我已经输入了,就当作我已经成功录入一本书了
2. 我采用了这种方式
iss >> p->book_Entry_number >> p->book_name >> p->author_name >> p->book_number >> p->publish_address >> p->publish_time >> p->book_price;
因为C++我才学不久,本来就是打算借这个机会练练手emm
所以“如果你的book类的operator>>重载是正确的,那么你应该可以直接使用iss >> *p 。如果不行,你就需要检查你的operator>>实现,确保它能正确处理从空格分隔的字符串流中读取。”并不是很理解
3. 这行代码
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
说我max未定义,但是这个应该是一个类里边的方法吧,咋会这样呢

铭凡 发表于 2023-6-12 23:37:26

isdkz 发表于 2023-6-12 23:15
看起来问题可能在于你的book类对输入流的处理方式。这可能是因为你的operator>>实现不适用于从空 ...

大佬我录了一个调试程序的视频,麻烦抽空帮忙看下,感激不尽!

链接:https://pan.baidu.com/s/1G2aM5fh7iPas5QxRG10Zaw
提取码:mfzd
--来自百度网盘超级会员V3的分享

isdkz 发表于 2023-6-12 23:38:55

铭凡 发表于 2023-6-12 23:29
你好,按照你的思路,我改了一下,代码如下




非常抱歉给你带来了困扰。针对你提出的问题,我给出以下建议:

1. 我怀疑你的输入可能被某处的 '\n' (换行符)捕获了,因此当你试图使用std::getline(std::cin, userInput);时,它立即返回了空字符串。你可以试着在该句之前添加std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); ,看看是否有所帮助。

2. 我建议你试试直接使用iss >> *p; ,但是确保你的operator>>重载可以从空格分隔的字符串流中正确读取。在你的book类中应该有一个类似于以下的方法:

friend std::istream& operator>>(std::istream& in, book& b) {
    in >> b.book_Entry_number >> b.book_name >> b.author_name >> b.book_number >> b.publish_address >> b.publish_time >> b.book_price;
    return in;
}


这样就可以直接使用iss >> *p;了。如果你的book类中并没有这样的方法,或者该方法的实现不正确,那么你就需要使用你之前的方式,即iss >> p->book_Entry_number >> p->book_name >> p->author_name >> p->book_number >> b.publish_address >> b.publish_time >> b.book_price; 。

3. 对于std::numeric_limits<std::streamsize>::max()未定义的问题,你需要在文件顶部加入#include <limits> ,这样std::numeric_limits才可以使用。如果你的编译器仍然提示错误,你可以尝试使用std::cin.ignore(1024, '\n');作为替代。

希望这些建议能帮到你!如果还有问题,请随时向我提问。
页: [1]
查看完整版本: 求助这个功能怎么实现呀!