在 cin 之后使用 getline(cin, s) [重复]

Posted

技术标签:

【中文标题】在 cin 之后使用 getline(cin, s) [重复]【英文标题】:Using getline(cin, s) after cin [duplicate] 【发布时间】:2011-04-21 05:29:21 【问题描述】:

我需要以下程序来获取整行用户输入并将其放入字符串名称中:

cout << "Enter the number: ";
int number;
cin >> number;

cout << "Enter names: ";
string names;

getline(cin, names);

但是,在 getline() 命令之前使用 cin &gt;&gt; number 命令(我猜这是问题所在),它不允许我输入名称。为什么?

我听说过一些关于 cin.clear() 命令的信息,但我不知道它是如何工作的,也不知道为什么它是必要的。

【问题讨论】:

假设您输入的是:5&lt;enter&gt;John&lt;enter&gt;。然后cin &gt;&gt; number 读取JUST 5. 将换行符(回车符)留在流中。因此,当您尝试使用 getline(cin,name) 读取名称时,它会读取到行尾。 但请注意有一个换行符可以读取(因此名称将为空(因为您没有读取 5 之后的换行符)。如果您想切换在 >> 和 getline() 之间,您需要小心输入的行尾。 @LokiAstari:这是一个比下面发布的任何一个更好的答案。可以这样发吗? 【参考方案1】:
cout << "Enter the number: ";
int number;
cin >> number;

cin.ignore(256, '\n'); // remaining input characters up to the next newline character
                       // are ignored

cout << "Enter names: ";
string names;
getline(cin, names);

【讨论】:

【参考方案2】:

另一种方法是放一个

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

在您的cin&gt;&gt;number; 之后完全刷新输入缓冲区(拒绝所有额外的字符,直到找到换行符)。您需要#include &lt;limits&gt; 才能获得max() 方法。

【讨论】:

@jonsca:“拒绝所有多余的字符”在大多数生产系统中都是可疑的......可以吃空白,但丢弃未知数据很容易且默默地导致错误结果。 @cnicutar 它因实施而异 @Tony 如果您有一个循环接收位于 cin 语句之后的字符,而不是 getline 怎么样?当然,额外的字符会对此产生影响。您是在谈论更多安全漏洞吗? “循环输入字符”...如果您的意思是 while (isspace(cin.peek())) cin.ignore()... 对我来说看起来不错。在上面,我在想更多的是用户误解了输入格式要求,或者某些脚本生成了输入中断,但是损坏的输入似乎被成功处理,因为它被忽略了——他们最终可能会相信损坏的结果。如果输入不符合规范,最好让程序生成错误。 @Tony 啊,好吧,我误解了你想说的话。关于验证的要点。【参考方案3】:
cout << "Enter the number: ";
int number;
if (cin >> number)

    // throw away the rest of the line 
    char c;
    while (cin.get(c) && c != '\n')
        if (!std::isspace(c))
        
            std::cerr << "ERROR unexpected character '" << c << "' found\n";
            exit(EXIT_FAILURE);
        
    cout << "Enter names: ";
    string name;
    // keep getting lines until EOF (or "bad" e.g. error reading redirected file)...
    while (getline(cin, name))
        ...use name...

else

    std::cerr << "ERROR reading number\n";
    exit(EXIT_FAILURE);

在上面的代码中,这个位...

    char c;
    while (cin.get(c) && c != '\n')
        if (!std::isspace(c))
        
            std::cerr << "ERROR unexpected character '" << c << "' found\n";
            exit(EXIT_FAILURE);
        

...在数字仅包含空格之后检查输入行的其余部分。

为什么不直接使用忽略?

这非常冗长,因此在&gt;&gt; x 之后在流上使用ignore 是一种经常推荐的替代方法,可以将内容丢弃到下一个换行符,但它有丢弃非空白内容的风险,这样做会忽略文件中的损坏数据。您可能关心也可能不关心,这取决于文件的内容是否受信任、避免处理损坏数据的重要性等。

那么你什么时候会使用 clear 和 ignore?

因此,std::cin.clear()(和std::cin.ignore())对此不是必需的,但对于删除错误状态很有用。例如,如果您想让用户有很多机会输入有效数字。

int x;
while (std::cout << "Enter a number: " &&
       !(std::cin >> x))

    if (std::cin.eof())
    
        std::cerr << "ERROR unexpected EOF\n";
        exit(EXIT_FAILURE);
    

    std::cin.clear();  // clear bad/fail/eof flags

    // have to ignore non-numeric character that caused cin >> x to
    // fail or there's no chance of it working next time; for "cin" it's
    // common to remove the entire suspect line and re-prompt the user for
    // input.
    std::cin.ignore(std::numeric_limits<std::streamsize>::max());

skipws 或类似的东西不能更简单吗?

另一个简单但半生不熟的替代 ignore 的原始要求是使用 std::skipws 在读取行之前跳过任何数量的空格...

if (std::cin >> number >> std::skipws)

    while (getline(std::cin, name))
        ...

...但是如果它得到像“1E6”这样的输入(例如,一些科学家试图输入 1,000,000,但 C++ 只支持浮点数的表示法)不会接受,你最终会得到number set到1E6 读取为name 的第一个值。另外,如果您有一个有效数字后跟一个或多个空行,这些行将被忽略。

【讨论】:

呃,这并不能回答问题或解决问题。 -1 @LightnessRacesinOrbit:它如何“不能解决问题”?对getline 的第一次调用会消耗数字后的换行符并循环,直到找到一个非空行......对我来说似乎是固定的。 OP的问题没有问“为什么?”问题发生了,但确实评论说他不确定为什么clear 可能是必要的 - 其他人在 2 天前编辑了这个 5 岁的问题以添加它,大大改变了要点。 现在你已经在[别人的]回答中编辑了,这样更好 @LightnessRacesinOrbit:我从 2011 年开始编辑了我对 jonsca 回答的评论的要点 - 没什么新意。【参考方案4】:

试试:

int number;

cin >> number;

char firstCharacterOfNames;
cin >> firstCharacterOfNames;  // This will discard all leading white space.
                               // including new-line if there happen to be any.

cin.unget();                   // Put back the first character of the name.

std::string  names;
std::getline(cin, names);      // Read the names;

或者。如果您知道数字和名称总是在不同的行上。

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

【讨论】:

【参考方案5】:

在使用 getline 之前,您可以使用 std::ws 提取输入缓冲区中的任何空白字符。 std::ws 的标头是 sstream。

cout << "Enter the number: ";
int number;
cin >> number;
cout << "Enter names: ";
string names;
cin>>ws;
getline(cin, names);

【讨论】:

【参考方案6】:

在 getline() 函数之前使用 cin 时尝试 cin.ignore()

void inputstu()
    cout << "Enter roll Number:";
    cin >> roll_no;
    cin.ignore(); //ignore the withspace and enter key
    cout << "Enter name:";
    getline(cin, stu_name);

【讨论】:

【参考方案7】:

或者你可以刷新输入缓冲区来读取字符串

fflush(stdin)

在头文件stdio.h中定义。

此代码有效..

cout << "Enter the number: ";
int number;
cin >> number;

cout << "Enter names: ";
string names;
fflush(stdin);  //FLUSHING STDIN
getline(cin, names);

【讨论】:

【参考方案8】:

我刚用过

getline(cin >> ws,lard.i_npute);

符合标准

#include <iostream>

header 在我遇到回车问题并且 ws 操纵器工作的情况下。我可能会开始将循环函数嵌入为类,并至少使用构造函数和析构函数调用。

【讨论】:

【参考方案9】:
cout << "Enter the number: ";
int number;
cin >> number;

cout << "Enter names: ";
string names;
getline(cin, names);//works on the \n left behind
getline(cin, names);//continues and rewrites names

它非常自我解释,cin &gt;&gt; number 使用的流中留下了一个 \n,它在第一次使用时被分配给名称。现在重用 getline 会写入正确的值。

【讨论】:

【参考方案10】:

你可以在cppreference找到你想要的答案。

在空格分隔的输入之后立即使用时,例如在int n; std::cin &gt;&gt; n; 之后,getline 消耗了 operator>> 留在输入流上的 endline 字符,并立即返回。一个常见的解决方案是在切换到面向行的输入之前忽略输入行中带有cin.ignore(std::numeric_limits&lt;std::streamsize&gt;::max(), '\n'); 的所有剩余字符。

【讨论】:

【参考方案11】:

您想在您的 cin 语句之后使用 cin.ignore(),因为您想在使用 cin 获取 int 变量后忽略缓冲区中留下的“\n”。

我有一个类似的程序用于解决类似的问题:

#include <iostream>
#include <iomanip>
#include <limits>

using namespace std;

int main() 
    int i = 4;
    double d = 4.0;
    string s = "HackerRank ";

    // Declare second integer, double, and String variables.
    int n;
    double d2;
    string str;

    // Read and save an integer, double, and String to your variables.
    cin >> n;
    cin >> d2;

    cin.ignore();

    getline(cin, str);

    // Print the sum of both integer variables on a new line.
    cout << i + n << endl;


    // Print the sum of the double variables on a new line.
    cout << d + d2 << endl;

    // Concatenate and print the String variables on a new line
    cout << s << str << endl;

    // The 's' variable above should be printed first.

    return 0;

【讨论】:

【参考方案12】:

从概念上讲,我认为您希望每个答案都整齐地排成一行。那你为什么不试试这个呢?

cout << "Enter the number: ";
string line;
getline(cin, line);
int number = std::stoi(line);

cout << "Enter names: ";
string names;
getline(cin, names);

代码正确使用第一个换行符,如果行正确,则为您提供数字,否则抛出异常。全部免费!

【讨论】:

【参考方案13】:
#include <iostream>
#include <string>

using namespace std;

int main()

    cout << "Enter the number: ";
    int number;
    cin >> number;
    cout << "Enter names: ";
    string names;

    // USE peek() TO SOLVE IT! ;)
    if (cin.peek() == '\n') 
        cin.ignore(1 /*numeric_limits<streamsize>::max()*/, '\n');
    

    getline(cin, names);

    return 0;

只需使用cin.peek() 往前看,看看'\n' 是否仍留在cin 的内部缓冲区中。如果是这样:忽略它(基本上跳过它)

【讨论】:

如果是'\r' 怎么办?这是一个非常脆弱的解决方案,我会在代码审查中拒绝。

以上是关于在 cin 之后使用 getline(cin, s) [重复]的主要内容,如果未能解决你的问题,请参考以下文章

在 getline 之后在 C++ 中输入

在 getline(cin, string) 之后使用 cin

cin.get(), cin.getline() , getline(cin,s) 三者的区别

关于cin,getline一起出现无法正常输入的问题

cin 和 getline 混用中需要注意的问题

关于 getline(cin, string) 的 C++ 快速问题