c ++ getline()在多次调用时不等待来自控制台的输入

Posted

技术标签:

【中文标题】c ++ getline()在多次调用时不等待来自控制台的输入【英文标题】:c++ getline() isn't waiting for input from console when called multiple times 【发布时间】:2011-12-08 21:01:17 【问题描述】:

我试图从控制台获取一些用户输入参数,两个字符串,两个整数和一个双精度。我正在尝试使用的相关代码是这样的:

#include <string>
#include <iostream>
using namespace std;

// ...

string inputString;
unsigned int inputUInt;
double inputDouble;

// ...

cout << "Title: "; 
getline(cin, inputString);
tempDVD.setTitle(inputString);

cout << "Category: "; 
getline(cin, inputString);
tempDVD.setCategory(inputString);

cout << "Duration (minutes): "; 
cin >> inputUInt; 
tempDVD.setDuration(inputUInt);

cout << "Year: "; 
cin >> inputUInt; 
tempDVD.setYear(inputUInt);

cout << "Price: $"; 
cin >> inputDouble; 
tempDVD.setPrice(inputDouble);

但是,在运行程序时,不是等待输入第一个 inputString,而是在第二个 getline() 调用之前代码不会停止。因此控制台输出如下所示:

标题:类别:

光标出现在类别之后。如果我现在输入,程序会跳转到年份输入,不允许我输入多个字符串。这里发生了什么?

【问题讨论】:

无法复制;请发布真实,完整的代码。我敢打赌你的问题出在别处。另外,不要混合格式化输入和getline() @KerrekSB:我同意混合它们是不良风格的表现,但不混合它们的客观原因是什么?我认为混合它们是完全有效的,真的。 @sehe:问题是格式化提取不消耗换行符,所以当你认为你已经处理了前面的所有行之后,当你做getline()时很容易得到意想不到的结果.我并不是说这是不可能的,但它通常会使逻辑非常难以阅读和维护。 抱歉代码不完整;该计划很长。我现在认为这个问题与以前使用 cin 在此块之前获取 int 有关。 【参考方案1】:

问题是您将 getline() 调用与运算符 >> 的使用混合在一起。

请记住,运算符 >> 忽略了前导空格,因此将正确地跨行边界继续。但是在成功检索输入后停止读取,因此不会吞下尾随的 '\n' 字符。因此,如果您在 >> 之后使用 getline(),除非您小心(首先删除未读取的 '\n' 字符),否则通常会得到错误的结果。

诀窍是不要同时使用这两种输入。选择合适的并坚持下去。

如果它是所有数字(或与运算符 >> 配合得很好的对象),那么只需使用运算符 >>(注意字符串是唯一与输入/输出不对称的基本类型(即不能很好地配合))。

如果输入包含需要 getline() 的字符串或内容组合,则仅使用 getline() 并从字符串中解析出数字。

std::getline(std::cin, line);
std::stringstream  linestream(line);

int  value;
linestream >> value;

// Or if you have boost:
std::getline(std::cin, line);
int  value = boost::lexical_cast<int>(line);

【讨论】:

【参考方案2】:

您需要刷新输入缓冲区。可以通过cin.clear(); cin.sync(); 完成。

【讨论】:

奇怪的是,它不适用于这些组合。它仅适用于std::cin.ignore()【参考方案3】:

你可以使用

cin.ignore();

或者正如@kernald 提到的那样使用

cin.clear();
cin.sync();

在使用 getline() 之前

【讨论】:

【参考方案4】:

如前所述使用cin.clear()使用正确的错误处理:

    cin.clear();
    cin.sync();

    cout << "Title: "; 
    if (!getline(cin, inputString))  exit 255;
    tempDVD.setTitle(inputString);

    cout << "Category: "; 
    if (!getline(cin, inputString))  exit 255;
    tempDVD.setCategory(inputString);

    cout << "Duration (minutes): "; 
    if (!(cin >> inputUInt)) exit 255; 
    tempDVD.setDuration(inputUInt);

    cout << "Year: "; 
    if (!(cin >> inputUInt)) exit 255; 
    tempDVD.setYear(inputUInt);

    cout << "Price: $"; 
    if (!(cin >> inputDouble)) exit 255; 
    tempDVD.setPrice(inputDouble);

【讨论】:

谢谢。该代码仅在同时使用 cin.clear() 和 cin.sync() 时才有效。 将 >> 运算符与 getline() 方法混合的最简单方法是在任何调用 getline 之前输入 cin.ignore() ,以便清除输入缓冲区中任何剩余的换行符上一个输入。【参考方案5】:

如果用户在 getline 之前的 cin 中的 \n 之前输入一个空格,则仅 ignore 本身是不够的,因此您必须使用此代码而不是单独使用 ignore()。例如 12345 \t \n 将不再起作用。 必须忽略所有未处理的字符。

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

cingetline 之间使用它。

【讨论】:

【参考方案6】:

也适用于ws。使用cin 命令读取数据后,您可以使用getline(cin &gt;&gt; ws, inputString)) 吃掉空格或换行符。

【讨论】:

【参考方案7】:

将 getline() 与输入流混合通常是一件坏事。理论上可以使用流手动处理遗留的脏缓冲区,但这是绝对应该避免的不必要的痛苦。

您最好使用控制台库来获取您的输入,这样可以为您抽象出脏活。

看看 TinyCon。您可以使用静态方法 tinyConsole::getLine() 来代替 getline 和流调用,并且可以根据需要多次使用它。

您可以在此处找到信息: https://sourceforge.net/projects/tinycon/

【讨论】:

【参考方案8】:

cin.sync(); 用这个代替 cin.ignore( 效果最好。

【讨论】:

以上是关于c ++ getline()在多次调用时不等待来自控制台的输入的主要内容,如果未能解决你的问题,请参考以下文章

C ++试图通过getline函数为函数调用获取用户输入值

可以在循环中多次使用 getline() 吗? - Cython,文件读取

为啥我可以在不使用 std::getline 的情况下调用 getline?

多次调用一个函数而不等待它完成

keilc中怎么使一个库函数不调用时不编译

覆盖 C 库函数,调用原始函数