【问题标题】:Pause Function it is Looping Forever暂停功能它永远循环
【发布时间】:2019-09-23 16:18:44
【问题描述】:

我正在尝试在 C++ 中实现暂停功能,但它一直在循环。

我正在使用 macOS,但我正在尝试创建一个可以在任何系统中使用的暂停功能...我相信我的 cin >> 没有从键盘捕获 '\n' 或 '\r' 并且它正在循环永远。

void Transferencia::pause() {
    char enter = 0;
    while(enter != '\n' && enter != '\r') {
        cout << "(Press Enter to Continue...) ";
        cin >> enter;
    }
    cin.clear();
}

我想暂停我的程序,直到用户按下“输入”键。 但即使我按下“输入/返回”,它也会一直循环......

【问题讨论】:

  • MAC 表示与 Mac 完全不同的东西。
  • enter 可以等于'\n' 并且 等于\r?
  • 提示:|| -> &amp;&amp;.
  • 你试过检查enter的值吗?就为了您可以“手动检查”您的while 条件?另外,想一想:在 Return == '\n' 的系统中,第一个条件为假,但后者为真;因为它是一个逻辑或,while 条件将始终通过。换句话说,您有两个互斥条件(在返回的情况下)和逻辑 OR;这将始终评估为真(同样,在按下 Return 键的情况下)。
  • 我一般用简单的:std::cout &lt;&lt; "Paused. Press ENTER to continue.\n"; std::cin.ignore(1000000, '\n');

标签: c++ pause


【解决方案1】:

一开始:enter != '\n' || enter != '\r' 是一个重言式:即使enter 确实等于其中一个字符,它不能等于另一个。因此,其中一项测试必须为真...当enter 不等于两个值时,您实际上希望留在循环中。

std::cin &gt;&gt; ... 在您按下回车之前不会读取数据,但它会丢弃换行符(实际上是所有空格)。因此, 只需要在没有循环的情况下正确读取一个字符(循环再次将获得一个无限循环)就足够了;单独:如果用户在按下“回车”键之前根本没有输入任何内容,则std::cin 没有字符可读取,我们仍在等待。

可以做的是阅读整行:

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

这也将接受空行,这正是您想要的(注意:没有循环!)。

编辑(从 cmets 偷来的;谢谢,Thomas Matthews):更优雅的方式是

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

因为它不会创建任何以后会被丢弃的额外资源(std::string 对象!)。

编辑 2:

根据上次输入操作的类型,可能仍会缓冲换行符(甚至更多数据),例如。 G。在int n; std::cin &gt;&gt; n; 之后。在这种情况下,您需要跳过尚未缓冲的输入。所以你需要忽略两次。

但是,如果最后一个输入操作已经使用了换行符(例如std::getline - 或者如果之前根本没有任何输入操作),那么这将导致用户不得不按两次回车。所以你需要检测之前发生了什么。

std::cin.rdbuf().in_avail() 允许您检测有多少字符尚未缓冲。所以你可以:

if(std::cin.rdbuf().in_avail())
{
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::cout << "press enter" << std::endl;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

在某些系统(包括我的系统)上,in_avail 可以返回 0,即使换行符尚未缓冲! std::cin.sync_with_stdio(false); 可以解决问题;您应该在第一次输入操作之前执行它。希望您不要混合使用 C++(流)和 C(scanfprintf 等)IO...

【讨论】:

  • 但我相信使用您提到的代码将使用户能够按任意键继续...我只想在按下回车键时继续程序。跨度>
  • 不。用户可以在按下'enter'键之前输入anything,但std::getline直到后者发生才会返回(否则它如何确定一行完成???)。实际上,实现Press ANY key to continue. 要复杂得多,依赖于操作系统特定的资源。
  • 如果我使用:cin.ignore... 或 getline.. 程序不会等待输入...知道为什么吗?
  • 您之前是否按过“回车”?您是否在 IDE 中使用您的程序?有时,IDE 控制台的行为会有所不同。
  • 只是为了确定:制作一个全新的程序,只有一个裸露的int main(void) { std::cin.ignore(std::numeric_limits&lt;std::streamsize&gt;::max(), '\n'); return 0; }——如果它没有失败,问题就在其他地方,如果它成功——那么我现在已经结束了......
【解决方案2】:

最简单的方法是使用getline()

cin &gt;&gt; 忽略空格,包括换行符。 getline() 将读取整行,包括换行符。但是,它不会将换行符复制到输出字符串。如果用户只是按回车键而没有其他任何东西,你最终会得到一个空字符串。

所以,为了获得你想要的行为,你可以像这样构建你的循环:

string line;
while(true)
{
    cout << "(Press Enter to Continue...) " << endl;
    getline(cin, line);

    if(line == "")
        break;
}

【讨论】:

  • 使用此代码,我的程序会忽略 getline()。
  • 忽略它怎么办?它不可能简单地跳过该函数调用。它到底在做什么?
  • 创建一个示例程序。将此代码用作main() 函数的主体并再次对其进行测试。这段代码本身没有理由不工作。还有其他事情发生。何时调用pause()?在什么条件下?
  • 当我调试时,我进入 getline 函数但只是通过了,看起来 getline 它正在从缓冲区中获取一些东西,但即使使用 cin.clear() 它也不会改变结果......
  • 实际情况并非如此。调试器不会跳过它,但 getline() 本质上是作为一个暂停函数发挥作用的。当它被调用时,它会暂停执行,直到用户按下回车键。然后它返回所有输入的字符,直到换行符。当您在该函数调用上设置断点时,断点不一定会触发,直到 getline() 返回。
【解决方案3】:

@Aconcagua 已经回答了你的问题,但这是我想补充的。

通常,为了处理计算机中的某种特定类型的事件,我们通常遵循event-driven 范式或event-callback。 这个想法是有一个事件循环等待新事件进入系统。在这种情况下,键盘是一个事件,然后事件循环调用event-callbackevent-callback 所做的是将输入的值与某些条件进行比较,然后执行其他一些任务(它可能会更改程序的某些状态或通知用户)。

这个想法是通过两种方式保持 CPU 忙碌。

  1. event-driven :在等待新事件时做其他任务
  2. multithreading:系统中有多个线程。这种方法的缺点是data-race

玩得开心

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-30
    • 1970-01-01
    • 2017-01-08
    相关资源
    最近更新 更多