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');
在 cin 和 getline 之间使用它。
【讨论】:
【参考方案6】:也适用于ws
。使用cin
命令读取数据后,您可以使用getline(cin >> ws, inputString)
) 吃掉空格或换行符。
【讨论】:
【参考方案7】:将 getline() 与输入流混合通常是一件坏事。理论上可以使用流手动处理遗留的脏缓冲区,但这是绝对应该避免的不必要的痛苦。
您最好使用控制台库来获取您的输入,这样可以为您抽象出脏活。
看看 TinyCon。您可以使用静态方法 tinyConsole::getLine() 来代替 getline 和流调用,并且可以根据需要多次使用它。
您可以在此处找到信息: https://sourceforge.net/projects/tinycon/
【讨论】:
【参考方案8】:cin.sync(); 用这个代替 cin.ignore( 效果最好。
【讨论】:
以上是关于c ++ getline()在多次调用时不等待来自控制台的输入的主要内容,如果未能解决你的问题,请参考以下文章
可以在循环中多次使用 getline() 吗? - Cython,文件读取