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

Rad*_*cus 51 c++ ignore cin getline

我用C++编写了一个非常基本的程序,它要求用户输入一个数字,然后输入一个字符串.令我惊讶的是,在运行程序时,它永远不会停止询问字符串.它只是跳过了它.在对StackOverflow进行一些阅读后,我发现我需要添加一行说:

cin.ignore(256, '\n');
Run Code Online (Sandbox Code Playgroud)

在获取字符串输入的行之前.添加修复问题并使程序正常工作.我的问题是为什么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";

}
Run Code Online (Sandbox Code Playgroud)

sav*_*ays 47

忽略正如名称所暗示的那样.

它不会"丢弃"你不需要的东西,它会忽略你调用它时指定的字符数量,直到你指定为断点的字符.

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

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

  • 你需要使用`numeric_limits <streamsize> :: max()`忽略所有字符,而不是1000. (14认同)
  • 不完全是一个缺陷,更像是精确度.从技术上讲,如果换行字符没有被读入,那么它就不会读取所有内容.输入缓冲区忽略空格,所以当你从std :: cin读取信息时,新行无关紧要.但是当你谈论getline时,它会将整行提升到换行符,当换行符是getline函数看到的第一件事就是它得到的全部. (5认同)
  • 谢谢。正如您所描述的那样,问为什么 C++ 存在在 cin 缓冲区中获取 '\n' 字符的问题是否太过分了?这是语言上的缺陷吗?或者是因为有某种目的而故意这样做的? (4认同)
  • 根据标准, .ignore() “提取并丢弃字符”,所以我认为这非常接近于丢弃 http://www.cplusplus.com/reference/istream/istream/ignore/ (2认同)

Him*_*rma 19

简答

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

什么时候?当您使用某些不独立的函数时,会忽略前导空格。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' ,以先发生的情况为准。


Dan*_*Dan 15

你正在考虑这个错误的方法.您每次都在考虑逻辑步骤cingetline使用它们.防爆.先问一个号码,然后问一个名字.这是错误的思考方式cin.所以你遇到竞争条件,因为你假设每次请求输入时流都是清晰的.

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

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

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

    cout << "num=" << num << ",mystr=\'" << mystr << "\'" << endl;
}
Run Code Online (Sandbox Code Playgroud)

在上面,你在想,"首先得到一个数字." 所以你输入123按回车键,你的输出就会出现num=123,mystr=''.这是为什么?这是因为在你拥有的流中123\n,当它仍然在流中时被123解析为num变量\n.getline默认情况下,读取doc 函数会istream直到\n遇到a.在这个例子中,因为\n它在流中,看起来它"跳过"它但它正常工作.

要使上述工作正常,您必须输入123Hello World正确输出的内容num=123,mystr='Hello World'.那个,或者你把它放在它cin.ignore之间cin,getline以便它会突破你期望的逻辑步骤.

这就是您需要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;
}
Run Code Online (Sandbox Code Playgroud)

以上似乎是合乎逻辑的步骤.首先询问名字,姓氏,然后是年龄.因此,如果您John输入,则Doe输入,然后19输入,应用程序将执行每个逻辑步骤.如果您在"流"中想到它,您只需输入John Doe 19"名字:"问题,它也会起作用,并且似乎跳过剩下的问题.为了使上述步骤按逻辑步骤工作,您需要为ignore问题中的每个逻辑中断提供剩余的流.

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


sha*_*een 5

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

一个非常常见的用例是使用它来安全地忽略换行符,因为cin有时会留下换行符,您将不得不移至新的输入行。

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