C++ 新手想问下关于 Linux 下如何实现类似 Windows 的 Pause 功能的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
BRS5672023
V2EX    C++

C++ 新手想问下关于 Linux 下如何实现类似 Windows 的 Pause 功能的问题

  •  
  •   BRS5672023 2024-10-18 20:17:48 +08:00 2469 次点击
    这是一个创建于 423 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近几天看了一点黑马程序员的视频(没什么基础),试着跟着写了一下实现通讯录管理的代码(暂时只完成了一部分功能),想要在 Linux 系统下实现类似 Windows 里 system("pause") 的功能,比如在通讯录中写完一个联系人的信息或者显示一个联系人的信息的时候能够 Pause 一下。。代码如下

    #include <iostream> using namespace std; #include <string> #include <limits> // 定义 pause 函数以及 getValidInput 函数中使用 #define MAX 1000 // 通讯录最大人数 void showMenu (); void pause (); int getValidInput (); // 联系人结构体 struct Person { string m_Name; int m_Gender; int m_Age; long m_Phone; string m_Address; }; // 通讯录结构体 struct Addressbooks { struct Person personArray[MAX]; int m_Size; // 通讯录中人员个数 }; void addPerson (Addressbooks *abs); void showPerson (Addressbooks *abs); int main () { struct Addressbooks abs; abs.m_Size = 0; while (true) { showMenu(); // 菜单调用 // cin >> select; // 检查输入是否有效 // if (cin.fail()) { // cin.clear(); // 清除错误状态 // cin.ignore(numeric_limits<streamsize>::max(),'\n'); // 清空缓冲区 // cout << "请输入有效的数字!" << endl; // continue; // 重新进入循环 // } int select = getValidInput (); switch (select) { case 1: // 添加联系人 addPerson(&abs); // 利用地址传递,可以修饰实参 break; case 2: showPerson(&abs); break; case 3: break; case 4: break; case 5: break; case 6: break; case 0: cout << "欢迎下次使用" << endl; // pause(); return 0; // break; default: cout << "请输入数字 1-6 或 0" << endl; break; } } return 0; } void showMenu () { cout << "1 、添加联系人" << endl; cout << "2 、显示联系人" << endl; cout << "3 、删除联系人" << endl; cout << "4 、查找联系人" << endl; cout << "5 、修改联系人" << endl; cout << "6 、清空联系人" << endl; cout << "0 、退出通讯录" << endl; } // 实现类似 Windows 系统上的 system("pause") 功能 void pause () { cin.clear(); // if (cin.eof()) { cin.ignore(numeric_limits<streamsize>::max(), '\n'); // 忽略输入流中的内容直到换行符,但因为输入内容已经被清空,这里程序会等待输入一个回车(换行符) // } cout << "请按回车键继续" << endl; cin.get(); } // 检测输入数据是否为整数,是则返回该输入 int getValidInput () { int input; while (true) { cin >> input; if (cin.fail()) { cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); cout << "请输入有效的数字!" << endl; } else { if (cin.eof()) { cin.ignore(numeric_limits<streamsize>::max(), '\n'); } return input; } } } // 添加联系人 void addPerson (Addressbooks *abs) { // 判断通讯录是否已满 if (abs->m_Size == MAX) { cout << "通讯录已满,无法添加联系人!" << endl; return; } else { string name; cout << "请输入联系人姓名:" << endl; cin >> name; abs->personArray[abs->m_Size].m_Name = name; cout << "请输入联系人性别:" << endl; cout << "输入数字 1 为男性" << endl; cout << "输入数字 2 为女性" << endl; while (true) { // cin >> gender; // if (cin.fail()) { // cin.clear(); // cin.ignore(numeric_limits<streamsize>::max(), '\n'); // cout << "请输入有效的数字!" << endl; // continue; // } int gender = getValidInput (); if (gender == 1 || gender == 2) { abs->personArray[abs->m_Size].m_Gender = gender; break; } cout << "输入有误,请重新输入" << endl; } cout << "请输入联系人年龄:" << endl; int age = getValidInput (); abs->personArray[abs->m_Size].m_Age = age; cout << "请输入联系人电话号码:" << endl; long phone; cin >> phone; abs->personArray[abs->m_Size].m_PhOne= phone; cout << "请输入联系人家庭住址:" << endl; string address; cin >> address; abs->personArray[abs->m_Size].m_Address = address; cout << "已成功添加联系人 " << abs->personArray[abs->m_Size].m_Name << endl; abs->m_Size++; pause(); system("clear"); // 对于 Windows 系统,应该使用 system("cls") } } void showPerson (Addressbooks *abs) { if (abs->m_Size == 0) { cout << "当前记录为空" << endl; } else { for (int i=0;i<abs->m_Size;i++) { cout << "姓名:" << abs->personArray[i].m_Name << endl; cout << "性别:" << abs->personArray[i].m_Gender << endl; cout << "年龄:" << abs->personArray[i].m_Age << endl; cout << "电话:" << abs->personArray[i].m_Phone << endl; cout << "地址:" << abs->personArray[i].m_Address << endl; } } pause(); system("clear"); } 

    然后我发现在我定义的函数 getValidInput 里面加入一个 cin.eof() 的判断就基本实现了我想要的效果,但其实我不太理解原因是什么,特别是如果我把 getValidInput 函数的这个判断给注释掉的话,那么在我输入 "2" 使用 "显示联系人" 这个功能时,需要再输入一个回车才会显示 "请按回车键继续" 的字符;而如果我仍然注释 getValidInput 中的这个判断,但取消 pause 函数定义中关于 cin.eof() 的注释(见上面的代码),那么在我输入 "1" 使用 "添加联系人" 的功能的时候,在我输入完联系人信息之后,pause() 似乎不会起作用,system("clear") 会直接清屏。。

    10 条回复    2024-10-19 18:48:55 +08:00
    cnbatch
        1
    cnbatch  
       2024-10-18 21:24:04 +08:00
    system()本质是运行命令行的命令,所以 system("pause")意思就是在 Windows 调用 pause 命令

    如果是想通用一点,那就把 system("pause")替换成
    printf("Press enter to continue");
    int c = getchar();
    ysc3839
        2
    ysc3839  
       
    好像要关掉行缓冲,然后就能接收到单个字符输入了,收到之后继续运行即可。
    yanqiyu
        3
    yanqiyu  
       2024-10-18 21:38:07 +08:00
    general: cin.eof 除非我按 Ctrl+D ,或者 pipe 进来个文件,否则始终是 false ,所以有那个判断大概就是等价于删掉它包起来的代码。(并且一般交互式程序遇到 end of cin 大概就该结束了)

    > 特别是如果我把 getValidInput 函数的这个判断给注释掉的话,那么在我输入 "2" 使用 "显示联系人" 这个功能时,需要再输入一个回车才会显示 "请按回车键继续" 的字符

    cin.ignore(numeric_limits<streamsize>::max(), '\n'); 会一直等输入(堵塞)直到遇到回车,要是缓冲区里面没有回车的话。

    > 而如果我仍然注释 getValidInput 中的这个判断,但取消 pause 函数定义中关于 cin.eof() 的注释(见上面的代码),那么在我输入 "1" 使用 "添加联系人" 的功能的时候,在我输入完联系人信息之后,pause() 似乎不会起作用,system("clear") 会直接清屏。。

    那大概是缓冲区里面 somehow 留了一个\n...要是没有前面的 ignore 把它耗掉它就把那个 std::cin.get() pass 掉了
    wshcdr
        4
    wshcdr  
       2024-10-18 21:38:58 +08:00
    #include <iostream>

    int main() {
    std::cout << "Press any key to continue..." << std::endl;
    std::cin.get(); // 等待用户按下一个键
    std::cout << "Continuing..." << std::endl;
    return 0;
    }
    sagaxu
        5
    sagaxu  
       2024-10-18 21:39:24 +08:00   1
    system("read -n 1")
    BRS5672023
        6
    BRS5672023  
    OP
       2024-10-18 22:23:23 +08:00
    @cnbatch 直接按照你给出的说法替换后在我进行添加联系人的操作后的输出结果是

    Press enter to continue1 、添加联系人
    2 、显示联系人
    3 、删除联系人
    4 、查找联系人
    5 、修改联系人
    6 、清空联系人
    0 、退出通讯录

    不太清楚怎么回事。。
    BRS5672023
        7
    BRS5672023  
    OP
       2024-10-18 22:27:31 +08:00
    @sagaxu 这个方法不错,感谢
    BRS5672023
        8
    BRS5672023  
    OP
       2024-10-18 22:47:27 +08:00
    @yanqiyu

    >> 特别是如果我把 getValidInput 函数的这个判断给注释掉的话,那么在我输入 "2" 使用 "显示联系人" 这个功能时,需要再输入一个回车才会显示 "请按回车键继续" 的字符

    > cin.ignore(numeric_limits<streamsize>::max(), '\n'); 会一直等输入(堵塞)直到遇到回车,要是缓冲区里面没有回车的话。

    这个地方为什么它在 case 1 和 case 2 的时候行为不一致呢?是因为我在使用 case 2 的 showPerson 函数里面没有任何输入所以需要我先输入一个回车吗?然后我加入的 cin.eof() 的判断就相当于把 cin.ignore 这一行给注释掉了所以在我一开始选择 case 的 getValidInput 里就会把我最初输入的 1 或者 2 给保留下来,然后 case 2 里的 pause 就不再需要我再输入一个换行符了,大概是这个原因?
    zwzwzwzwzxt
        9
    zwzwzwzwzxt  
       2024-10-19 11:20:27 +08:00
    @sagaxu #5 read 是 shell 内建的命令,最好 "bash -c 'read -n 1'" 指定一下不然可能会有问题。
    yanqiyu
        10
    yanqiyu  
       2024-10-19 18:48:55 +08:00
    @BRS5672023 #8 一般我也不会太细究为什么,毕竟研究 iobuffer 行为大概率会变成无用功(这方面折腾不如用现成的 TUI 库),但是原因大概是 cin 的流操作会留一个\n 在 buffer 里面(对应的 getline 不会)

    可能有些路径没有最后一个(输入的)换行之前用的 cin >>, 然后\n 就留给了最后的 cin.get();然后退出了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     865 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 20:44 PVG 04:44 LAX 12:44 JFK 15:44
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86