何时以及为什么需要在 C++ 中使用 cin.ignore()?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25475384/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:19:31  来源:igfitidea点击:

When and why do I need to use cin.ignore() in C++?

c++cingetlineignore

提问by Raddicus

I wrote a very basic program in C++ which asked the user to input a number and then a string. To my surprise, when running the program it never stopped to ask for the string. It just skipped over it. After doing some reading on StackOverflow, I found out that I needed to add a line that said:

我用 C++ 编写了一个非常基本的程序,它要求用户输入一个数字,然后输入一个字符串。令我惊讶的是,在运行程序时,它从未停止请求字符串。它只是跳过了它。在对 StackOverflow 进行了一些阅读后,我发现我需要添加一行内容:

cin.ignore(256, '\n');

before the line that gets the string input. Adding that fixed the problem and made the program work. My question is why does C++ need this cin.ignore()line and how can I predict when I will need to use cin.ignore()?

在获取字符串输入的行之前。添加它解决了问题并使程序运行。我的问题是为什么 C++ 需要这cin.ignore()条线,我如何预测何时需要使用cin.ignore()

Here is the program I wrote:

这是我写的程序:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    double num;
    string mystr;

    cout << "Please enter a number: " << "\n";
    cin >> num;
    cout << "Your number is: " << num << "\n";
    cin.ignore(256, '\n'); // Why do I need this line?
    cout << "Please enter your name: \n";
    getline (cin, mystr);
    cout << "So your name is " << mystr << "?\n";
    cout << "Have a nice day. \n";

}

采纳答案by savageWays

Ignore is exactly what the name implies.

忽略正是顾名思义。

It doesn't "throw away" something you don't need instead, it ignores the amount of characters you specify when you call it, up to the char you specify as a breakpoint.

它不会“丢弃”您不需要的东西,而是会忽略您在调用它时指定的字符数量,直到您指定为断点的字符。

It works with both input and output buffers.

它适用于输入和输出缓冲区。

Essentially, for std::cinstatements you use ignore before you do a getlinecall, because when a user inputs something with std::cin, they hit enter and a '\n'char gets into the cinbuffer. Then if you use getline, it gets the newline char instead of the string you want. So you do a std::cin.ignore(1000,'\n')and that should clear the buffer up to the string that you want. (The 1000 is put there to skip over a specific amount of chars before the specified break point, in this case, the \n newline character.)

本质上,对于std::cingetline调用之前使用 ignore 的语句,因为当用户使用 输入某些内容时std::cin,他们按回车键并且一个'\n'字符进入cin缓冲区。然后,如果您使用getline,它会获取换行符而不是您想要的字符串。所以你做了一个std::cin.ignore(1000,'\n'),这应该清除缓冲区直到你想要的字符串。(将 1000 放在那里是为了在指定的断点之前跳过特定数量的字符,在本例中为 \n 换行符。)

回答by Dan

You're thinking about this the wrong way. You're thinking in logical steps each time cinor getlineis used. Ex. First ask for a number, then ask for a name. That is the wrong way to think about cin. So you run into a race condition because you assume the stream is clear each time you ask for a input.

你正在以错误的方式思考这个问题。您每次都在按逻辑步骤思考cingetline使用。前任。先问号码,再问名字。那是错误的思考方式cin。因此,您遇到了竞争条件,因为您每次请求输入时都假设流是畅通的。

If you write your program purely for input you'll find the problem:

如果您编写程序纯粹是为了输入,您会发现问题:

void main(void)
{
    double num;
    string mystr;

    cin >> num;
    getline(cin, mystr);

    cout << "num=" << num << ",mystr=\'" << mystr << "\'" << endl;
}

In the above, you are thinking, "first get a number." So you type in 123press enter, and your output will be num=123,mystr=''. Why is that? It's because in the stream you have 123\nand the 123is parsed into the numvariable while \nis still in the stream. Reading the doc for getlinefunction by default it will look in the istreamuntil a \nis encountered. In this example, since \nis in the stream, it looks like it "skipped" it but it worked properly.

在上面,你在想,“先得到一个数字”。所以你输入123按回车,你的输出将是num=123,mystr=''. 这是为什么?这是因为在您拥有的流中,123\n并且仍然在流中时被123解析为num变量\ngetline默认情况下阅读函数的文档,它会查看istream直到\n遇到 a 。在这个例子中,由于\n在流中,看起来它“跳过”了它,但它工作正常。

For the above to work, you'll have to enter 123Hello Worldwhich will properly output num=123,mystr='Hello World'. That, or you put a cin.ignorebetween the cinand getlineso that it'll break into logical steps that you expect.

要使上述工作正常运行,您必须输入123Hello World哪个将正确输出num=123,mystr='Hello World'. 那,或者你cin.ignorecinand之间加上一个,getline这样它就会分解成你期望的逻辑步骤。

This is why you need the ignorecommand. Because you are thinking of it in logical steps rather than in a stream form so you run into a race condition.

这就是您需要ignore命令的原因。因为您是以逻辑步骤而不是流形式考虑它,所以您遇到了竞争条件。

Take another code example that is commonly found in schools:

再举一个学校中常见的代码示例:

void main(void)
{
    int age;
    string firstName;
    string lastName;

    cout << "First name: ";
    cin >> firstName;

    cout << "Last name: ";
    cin >> lastName;

    cout << "Age: ";
    cin >> age;

    cout << "Hello " << firstName << " " << lastName << "! You are " << age << " years old!" << endl;
}

The above seems to be in logical steps. First ask for first name, last name, then age. So if you did Johnenter, then Doeenter, then 19enter, the application works each logic step. If you think of it in "streams" you can simply enter John Doe 19on the "First name:" question and it would work as well and appear to skip the remaining questions. For the above to work in logical steps, you would need to ignorethe remaining stream for each logical break in questions.

以上似乎是合乎逻辑的步骤。首先询问名字,姓氏,然后是年龄。因此,如果您确实John输入,然后Doe输入,然后19输入,则应用程序会在每个逻辑步骤中工作。如果你在“流”中想到它,你可以简单地输入John Doe 19“名字:”问题,它也可以工作,并且似乎跳过剩余的问题。为了使上述内容按逻辑步骤工作,您需要ignore针对问题中的每个逻辑中断使用剩余的流。

Just remember to think of your program input as it is reading from a "stream" and not in logical steps. Each time you call cinit is being read from a stream. This creates a rather buggy application if the user enters the wrong input. For example if you entered a character where a cin >> doubleis expected, the application will product a rather (seemingly) bizarre output.

请记住将您的程序输入视为从“流”中读取而不是在逻辑步骤中读取。每次调用cin它时都是从流中读取的。如果用户输入错误,这会创建一个相当错误的应用程序。例如,如果您输入了一个cin >> double预期为a 的字符,应用程序将产生一个相当(看似)奇怪的输出。

回答by CodeTalker

Short answer

简答

Why? Because there is still whitespace (carriage returns, tabs, spaces, newline) left in the input stream.

为什么?因为输入流中仍有空格(回车、制表符、空格、换行符)。

When? When you are using some function which does not on their own ignores the leading whitespaces. Cin by default ignores and removes the leading whitespace but getline does not ignore the leading whitespace on its own.

什么时候?当您使用某些不独立的函数时,会忽略前导空格。Cin 默认会忽略并删除前导空格,但 getline 不会自行忽略前导空格。

Now a detailed answer.

现在详细解答。

Everything you input in the console is read from the standard stream stdin. When you enter something, let's say 256 in your case and press enter, the contents of the stream become 256\n. Now cin picks up 256 and removes it from the stream and \nstill remaining in the stream. Now next when you enter your name, let's say Raddicus, the new contents of the stream is \nRaddicus.

您在控制台中输入的所有内容都是从标准流 stdin 中读取的。当您输入某些内容时,例如在您的情况下为 256 并按 Enter,流的内容将变为256\n. 现在 cin 获取 256 并将其从流中删除并\n仍然保留在流中。现在,接下来当您输入您的姓名时,假设Raddicus流的新内容是\nRaddicus

Now here comes the catch. When you try to read a line using getline, if not provided any delimiter as the third argument, getline by default reads till the newline character and removes the newline character from the stream. So on calling new line, getline reads and discards \nfrom the stream and resulting in an empty string read in mystr which appears like getline is skipped (but it's not) because there was already an newline in the stream, getline will not prompt for input as it has already read what it was supposed to read.

现在问题来了。当您尝试使用 getline 读取一行时,如果没有提供任何分隔符作为第三个参数,getline 默认读取直到换行符并从流中删除换行符。因此,在调用新行时,getline\n从流中读取和丢弃并导致在 mystr 中读取一个空字符串,它看起来像 getline 被跳过(但事实并非如此),因为流中已经有一个换行符,getline 不会提示输入它已经阅读了它应该阅读的内容。

Now, how does cin.ignore help here?

现在,cin.ignore 在这里有什么帮助?

According to the ignore documentation extract from cplusplus.com-

根据来自cplusplus.com的忽略文档摘录-

istream& ignore (streamsize n = 1, int delim = EOF);

Extracts characters from the input sequence and discards them, until either n characters have been extracted, or one compares equal to delim.

The function also stops extracting characters if the end-of-file is reached. If this is reached prematurely (before either extracting n characters or finding delim), the function sets the eofbit flag.

istream& ignore (streamsize n = 1, int delim = EOF);

从输入序列中提取字符并丢弃它们,直到提取了 n 个字符,或者一个比较等于 delim。

如果到达文件末尾,该函数也会停止提取字符。如果过早地达到了这一点(在提取 n 个字符或找到 delim 之前),该函数将设置 eofbit 标志。

So, cin.ignore(256, '\n');, ignores first 256 characters or all the character untill it encounters delimeter (here \n in your case), whichever comes first (here \n is the first character, so it ignores until \n is encountered).

因此,cin.ignore(256, '\n');, 忽略前 256 个字符或所有字符,直到遇到分隔符(在您的情况下为 \n ),以先到者为准(此处 \n 是第一个字符,因此它会忽略直到遇到 \n )。

Just for your reference, If you don't exactly know how many characters to skip and your sole purpose is to clear the stream to prepare for reading a string using getline or cin you should use cin.ignore(numeric_limits<streamsize>::max(),'\n').

仅供参考,如果您不确切知道要跳过多少个字符,而您的唯一目的是清除流以准备使用 getline 或 cin 读取字符串,则应使用cin.ignore(numeric_limits<streamsize>::max(),'\n').

Quick explanation:It ignores the characters equal to maximum size of stream or until a '\n' is encountered, whichever case happens first.

快速解释:它忽略等于流的最大大小的字符或直到遇到 '\n' ,以先发生的情况为准。

回答by shafeen

When you want to throw away a specific number of characters from the input stream manually.

当您想手动从输入流中丢弃特定数量的字符时。

A very common use case is using this to safely ignore newline characters since cin will sometimes leave newline characters that you will have to go over to get to the next line of input.

一个非常常见的用例是使用它来安全地忽略换行符,因为 cin 有时会留下换行符,您必须跳过这些换行符才能进入下一行输入。

Long story short it gives you flexibility when handling stream input.

长话短说,它在处理流输入时为您提供了灵活性。

回答by vinod

Ignore function is used to skip(discard/throw away) characters in the input stream. Ignore file is associated with the file istream. Consider the function below ex: cin.ignore(120,'/n'); the particular function skips the next 120 input character or to skip the characters until a newline character is read.

忽略功能用于跳过(丢弃/丢弃)输入流中的字符。忽略文件与文件 istream 相关联。考虑下面的函数,例如:cin.ignore(120,'/n'); 特定函数跳过下一个 120 个输入字符或跳过这些字符直到读取换行符。

回答by Pikachu

As pointed right by many other users. It's because there may be whitespace or a newline character.

正如许多其他用户所指出的那样。这是因为可能有空格或换行符。

Consider the following code, it removes all the duplicate characters from a given string.

考虑下面的代码,它从给定的字符串中删除所有重复的字符。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int t;
    cin>>t;
    cin.ignore(); //Notice that this cin.ignore() is really crucial for any extra whitespace or newline character
    while(t--){
        vector<int> v(256,0);
        string s;
        getline(cin,s);
        string s2;
        for(int i=0;i<s.size();i++){
            if (v[s[i]]) continue;
            else{
                s2.push_back(s[i]);
                v[s[i]]++;
            }
        }
        cout<<s2<<endl;
    }
    return 0;
}

So, You get the point that it will ignore those unwanted inputs and will get the job done.

因此,您明白它会忽略那些不需要的输入并完成工作。

回答by Mahmud_28

It is better to use scanf(" %[^\n]",str) in c++ than cin.ignore() after cin>> statement.To do that first you have to include < cstdio > header.

在 c++ 中使用 scanf(" %[^\n]",str) 比在 cin>> 语句之后使用 cin.ignore() 更好。要做到这一点,首先必须包含 < cstdio > 标头。