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

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

本文关键字:cin ignore c++ 为什么 何时      更新时间:2023-10-16

我用c++写了一个非常基本的程序,要求用户先输入一个数字,然后输入一个字符串。令我惊讶的是,当运行程序时,它从来没有停下来询问字符串。它只是跳过了它。在阅读了StackOverflow之后,我发现我需要添加一行:

cin.ignore(256, 'n');

放在获取字符串输入的行之前。添加了这些内容,就可以修复问题并使程序正常工作。我的问题是为什么c++需要cin.ignore()行,以及我如何预测何时需要使用cin.ignore() ?

下面是我写的程序:

#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";
}

ignore做的正是名字所暗示的。

它不会';throw away ';你不需要的东西。相反,它会忽略调用它时指定的字符数,直到指定为分隔符的字符。

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

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

您考虑这个的方式是错误的。每次使用cingetline时,您都在逻辑步骤中进行思考。首先要一个号码,然后要一个名字。这是对cin的错误理解。因此,您会遇到竞争条件,因为您假设每次请求输入时流都是清空的。

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

int main()
{
    double num;
    string mystr;
    cin >> num;
    getline(cin, mystr);
    cout << "num=" << num << ",mystr='" << mystr << "'" << endl;
}

在上面,你会想,"首先得到一个数字。"因此,您输入123并按enter键,您的输出将是num=123,mystr=''。为什么呢?这是因为在流中有123n, 123被解析为num变量,而n仍在流中。默认情况下,读取getline函数的文档,它将查找istream,直到遇到n。在本例中,由于n在流中,因此看起来它"跳过"了。

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

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

再举一个学校里常见的代码例子:

int main()
{
    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;
}

以上似乎是合乎逻辑的步骤。先问名字,再问姓氏,然后问年龄。因此,如果执行John输入,然后执行Doe输入,然后执行19输入,则应用程序可以在每个逻辑步骤中工作。如果你用"流"来思考它;你可以简单地在"名字"后面输入John Doe 19。问题,它也会工作,似乎跳过剩下的问题。要使上面的步骤在逻辑步骤中工作,您需要为问题中的每个逻辑中断对剩余的流进行ignore

只要记住把你的程序输入想象成从一个"流"中读取。而且没有逻辑步骤。每次调用cin时,它都是从流中读取的。如果用户输入了错误的输入,这将创建一个相当有bug的应用程序。例如,如果您输入的字符应该是cin >> double,那么应用程序将产生一个看起来很奇怪的输出。

简短回答

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

什么时候?当你使用一些函数时,它们自己不会忽略前导空格。默认情况下,Cin会忽略并删除前导空格,但getline本身不会忽略前导空格。

现在是详细的答案

在控制台中输入的所有内容都是从标准流stdin中读取的。当您输入某些内容时,假设在您的示例中为256并按enter键,流的内容将变为256n。现在cin拾取256并将其从流中移除,n仍然留在流中。现在,当您输入您的名称时,比如Raddicus,流的新内容是nRaddicus

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

现在,我们来看看忽略这里的帮助?

根据忽略文档从cplusplus.com中提取-

istream&

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

如果文件结束符是,该函数也会停止提取字符达成。如果提前达到这个值(在提取n之前)字符或查找delim),该函数设置eofbit标志。

因此,cin.ignore(256, 'n');忽略前256个字符或所有字符,直到遇到分隔符(这里是n),以先到者为准(这里n是第一个字符,所以它忽略直到遇到n)。

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

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

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

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

长话短说,它给你处理流输入时的灵活性。

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

许多其他用户都指出了这一点。这是因为可能有空格或换行符。

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

#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;
}

所以,你知道它会忽略那些不需要的输入并完成工作。

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