鱼C论坛

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

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

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

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

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

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

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

它的原代码如下
void  LibraryManager::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);
        }
}

然后我改之后的如下
void  LibraryManager::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');了,为啥缓冲区的错误还是存在呢?
想知道小甲鱼最近在做啥?请访问 -> 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  对象的输入运算符已经正确重载。
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  对象中读取数据。
想知道小甲鱼最近在做啥?请访问 -> 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 显示图书信息#############
#############输入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继续,不管我输入什么,它都说我输入错误, 请重试
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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' 中的一个,那么会清空输入流并忽略剩余的输入,然后提示用户重新输入。当输入正确时,循环才会结束。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 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未定义,但是这个应该是一个类里边的方法吧,咋会这样呢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

大佬我录了一个调试程序的视频,麻烦抽空帮忙看下,感激不尽!
链接:https://pan.baidu.com/s/1G2aM5fh7iPas5QxRG10Zaw 
提取码:mfzd 
--来自百度网盘超级会员V3的分享
想知道小甲鱼最近在做啥?请访问 -> 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  类中应该有一个类似于以下的方法:
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');  作为替代。

希望这些建议能帮到你!如果还有问题,请随时向我提问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-9-28 01:17

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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