繁体   English   中英

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

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

我用 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";

}

忽略正是顾名思义。

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

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

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

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

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

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

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

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

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

要使上述工作正常运行,您必须输入123Hello World才能正确输出num=123,mystr='Hello World' 那,或者您在cingetline之间放置一个cin.ignore ,以便它分解为您期望的逻辑步骤。

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

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

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

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

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

简答

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

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

现在详细解答。

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

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

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

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

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

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

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

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

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

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

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

一个非常常见的用例是使用它来安全地忽略换行符,因为 cin 有时会留下换行符,您必须转到下一行输入。

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

忽略功能用于跳过(丢弃/丢弃)输入流中的字符。 忽略文件与文件 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() 更好。要做到这一点,首先必须包含 < cstdio > 标头。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM