鱼C论坛

 找回密码
 立即注册
查看: 1499|回复: 6

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

[复制链接]
发表于 2023-6-12 19:56:08 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

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

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

它的原代码如下
  1. void  LibraryManager::Add_book(book **q)//增加图书信息
  2. {
  3.         char m;

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

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

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

  8.         std::cin >> *p;

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

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

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

  31.         if (m == 'Y' || m == 'y')
  32.         {
  33.                 Add_book(&abook);
  34.                 exit(EXIT_SUCCESS);
  35.         }
  36.         else if (m == 'N' || m == 'n')
  37.         {
  38.                 std::cout << "正在返回到菜单,请勿操作" << std::endl;
  39.                 Sleep(1500);//停滞1.5s再继续
  40.                 system("cls");//清屏
  41.                 Menu();
  42.                 exit(EXIT_SUCCESS);
  43.         }
  44. }
复制代码


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

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

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

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

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

  16.         if ((ifReturn.compare("Return")) == 0)
  17.         {
  18.                 std::cout << "正在返回到菜单,请勿操作" << std::endl;
  19.                 Sleep(1500);//停滞1.5s再继续
  20.                 system("cls");//清屏
  21.                 Menu();
  22.                 exit(EXIT_SUCCESS);
  23.         }
  24.         else
  25.         {
  26.                 std::stringstream ss(ifReturn);
  27.                 std::cin.rdbuf(ss.rdbuf());
  28.         }
  29.         std::cin >> *p;

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

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

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

  52.         if (m == 'Y' || m == 'y')
  53.         {
  54.                 Add_book(&abook);
  55.                 exit(EXIT_SUCCESS);
  56.         }
  57.         else if(m == 'N' || m == 'n')
  58.         {
  59.                 std::cout << "正在返回到菜单,请勿操作" << std::endl;
  60.                 Sleep(1500);//停滞1.5s再继续
  61.                 system("cls");//清屏
  62.                 Menu();
  63.                 exit(EXIT_SUCCESS);
  64.         }
  65. */
  66. }
复制代码


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

另外,明明都已经用了cin.clear();还有cin.ignore(100, '\n');了,为啥缓冲区的错误还是存在呢?
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 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  对象的输入运算符已经正确重载。

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

  4.     book *p;
  5.     p = new book;

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

  10.     if (userInput == "Return") {
  11.         std::cout << "正在返回到菜单,请勿操作" << std::endl;
  12.         Sleep(1500);
  13.         system("cls");
  14.         Menu();
  15.         exit(EXIT_SUCCESS);
  16.     }
  17.     else {
  18.         std::istringstream iss(userInput);
  19.         iss >> *p;

  20.         if (*q == NULL) {
  21.             p->next = NULL;
  22.             *q = p;
  23.         }
  24.         else {
  25.             p->next = NULL;
  26.             (zbook)->next = p;
  27.         }

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

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

  39.         if (m == 'Y' || m == 'y') {
  40.             Add_book(&abook);
  41.             exit(EXIT_SUCCESS);
  42.         }
  43.         else if (m == 'N' || m == 'n') {
  44.             std::cout << "正在返回到菜单,请勿操作" << std::endl;
  45.             Sleep(1500);
  46.             system("cls");
  47.             Menu();
  48.             exit(EXIT_SUCCESS);
  49.         }
  50.     }
  51. }
复制代码


注意: 你需要确保  book  对象的输入运算符已经正确重载,以支持从  std::istringstream  对象中读取数据。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-12 23:11:45 | 显示全部楼层
本帖最后由 铭凡 于 2023-6-12 23:16 编辑
isdkz 发表于 2023-6-12 22:19
在你的代码中,你尝试使用  std::stringstream  对象来接受用户输入,然后再将它的缓冲区设置为  std::cin  ...


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

  18. 1 2 3 4 5 6 7
  19. 输入错误,请重新输入:
复制代码


然后我调试程序的时候,
  1. std::string userInput;
  2.         std::getline(std::cin, userInput);
复制代码


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

然后我输入Y继续,不管我输入什么,它都说我输入错误, 请重试
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-12 23:15:23 | 显示全部楼层
铭凡 发表于 2023-6-12 23:11
还是不行
执行结果如下:

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

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

  1. std::istringstream iss(userInput);
  2. 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' 的字符)时,你需要清空缓冲区并忽略剩余的输入,然后再尝试读取。你可以尝试如下的循环:

  1. do {
  2.     std::cin >> m;
  3.     if (m != 'Y' && m != 'y' && m != 'N' && m != 'n') {
  4.         std::cout << "输入错误,请重新输入:" << std::endl;
  5.         std::cin.clear();
  6.         std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
  7.     }
  8. } while (m != 'Y' && m != 'y' && m != 'N' && m != 'n');
复制代码


在这个循环中,如果输入的不是 'Y', 'y', 'N', 'n' 中的一个,那么会清空输入流并忽略剩余的输入,然后提示用户重新输入。当输入正确时,循环才会结束。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

  3.         book *p;
  4.         p = new book;

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

  6.         std::string userInput;
  7.         std::getline(std::cin, userInput);

  8.         if (userInput == "Return")
  9.         {
  10.                 std::cout << "正在返回到菜单,请勿操作" << std::endl;
  11.                 Sleep(1500);
  12.                 system("cls");
  13.                 Menu();
  14.                 exit(EXIT_SUCCESS);
  15.         }
  16.         else
  17.         {
  18.                 std::istringstream iss(userInput);
  19.                 iss >> p->book_Entry_number >> p->book_name >> p->author_name >> p->book_number >> p->publish_address >> p->publish_time >> p->book_price;

  20.                 if (*q == NULL)
  21.                 {
  22.                         p->next = NULL;
  23.                         *q = p;
  24.                 }
  25.                 else
  26.                 {
  27.                         p->next = NULL;
  28.                         (zbook)->next = p;
  29.                 }

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

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

  43.                 if (m == 'Y' || m == 'y')
  44.                 {
  45.                         Add_book(&abook);
  46.                         exit(EXIT_SUCCESS);
  47.                 }
  48.                 else if (m == 'N' || m == 'n')
  49.                 {
  50.                         std::cout << "正在返回到菜单,请勿操作" << std::endl;
  51.                         Sleep(1500);
  52.                         system("cls");
  53.                         Menu();
  54.                         exit(EXIT_SUCCESS);
  55.                 }
  56.         }
复制代码


所以。。。现在就出现了新的问题:
1. 我现在根本没办法输入书籍信息, 因为
  1. std::string userInput;
  2.         std::getline(std::cin, userInput);
复制代码

这两行执行之后,人家就自动以为我已经输入了,就当作我已经成功录入一本书了
2. 我采用了这种方式
  1. 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. 这行代码
  1. std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
复制代码

说我max未定义,但是这个应该是一个类里边的方法吧,咋会这样呢
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

  1. 链接:https://pan.baidu.com/s/1G2aM5fh7iPas5QxRG10Zaw
  2. 提取码:mfzd
  3. --来自百度网盘超级会员V3的分享
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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  类中应该有一个类似于以下的方法:

  1. friend std::istream& operator>>(std::istream& in, book& b) {
  2.     in >> b.book_Entry_number >> b.book_name >> b.author_name >> b.book_number >> b.publish_address >> b.publish_time >> b.book_price;
  3.     return in;
  4. }
复制代码


这样就可以直接使用  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');  作为替代。

希望这些建议能帮到你!如果还有问题,请随时向我提问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-10 02:18

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表