Why would we call cin.clear() and cin.ignore() after reading input?

Google Code University's C++ tutorial used to have this code:

// Description: Illustrate the use of cin to get input
// and how to recover from errors.


#include <iostream>
using namespace std;


int main()
{
int input_var = 0;
// Enter the do while loop and stay there until either
// a non-numeric is entered, or -1 is entered.  Note that
// cin will accept any integer, 4, 40, 400, etc.
do {
cout << "Enter a number (-1 = quit): ";
// The following line accepts input from the keyboard into
// variable input_var.
// cin returns false if an input operation fails, that is, if
// something other than an int (the type of input_var) is entered.
if (!(cin >> input_var)) {
cout << "Please enter numbers only." << endl;
cin.clear();
cin.ignore(10000,'\n');
}
if (input_var != -1) {
cout << "You entered " << input_var << endl;
}
}
while (input_var != -1);
cout << "All done." << endl;


return 0;
}

What is the significance of cin.clear() and cin.ignore()? Why are the 10000 and \n parameters necessary?

268454 次浏览

cin.clear()清除了 cin上的错误标志(这样以后的 I/O 操作就可以正常工作) ,然后 cin.ignore(10000, '\n')跳到下一个换行(忽略与非数字同一行上的其他内容,这样就不会导致另一个解析失败)。它只会跳过最多10000个字符,因此代码假设用户不会放入一个非常长的、无效的行。

你输入

if (!(cin >> input_var))

语句,如果从 cin 获取输入时发生错误。如果发生错误,则设置错误标志,以后获取输入的尝试将会失败。这就是为什么你需要

cin.clear();

去掉错误标志。而且,失败的输入会在我假设的某种缓冲区中。当您再次尝试获取输入时,它将在缓冲区中读取相同的输入,然后再次失败。这就是为什么你需要

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

它从缓冲区中取出10000个字符,但如果遇到换行符(n)则停止。10000只是一个通用的大值。

使用 cin.ignore(1000,'\n')来清除缓冲区中前一个 cin.get()的所有字符,它会选择在首先遇到’n’或者 1000 chars时停止。

我们为什么使用:

1) Cin 忽略

2)干净

?

简单来说:

1)忽略(提取和丢弃)我们不希望在流上的值

2)清除水流的内部状态。在使用 cin.clear 之后,内部状态再次设置为 goodbit,这意味着不存在“错误”。

长话短说:

如果某些东西被放到“流”(cin)中,那么它必须从那里获得。我们说的“采取”是指从流中“使用”、“移除”、“提取”。溪流有流动。数据就像溪流中的水一样流动着。你根本无法阻止水的流动;)

看看这个例子:

string name; //line 1
cout << "Give me your name and surname:"<<endl;//line 2
cin >> name;//line 3
int age;//line 4
cout << "Give me your age:" <<endl;//line 5
cin >> age;//line 6

如果用户回答第一个问题“ Arkadiusz Wlodarczyk”会发生什么?

Run the program to see for yourself.

您将在控制台上看到“ Arkadiusz”,但程序不会要求您提供“年龄”。它将刚刚完成后立即印刷“ Arkadiusz”。

而“ Wlodarczyk”没有显示。它似乎是如果它走了(?) *

发生了什么事? ; -)

因为“ Arkadiusz”和“ Wlodarczyk”之间有个空格。

名字和姓氏之间的“空格”字符是计算机的一个符号,表示在“输入”流上有两个等待提取的变量。

计算机认为你正在尝试发送输入多个变量。那个“太空”符号是他用这种方式解释的标志。

因此,计算机将“ Arkadiusz”赋值给“ name”(2) ,并且因为您在流(输入)中放入了多个字符串,所以计算机将尝试将值“ Wlodarczyk”赋值给变量“ age”(!).用户将没有机会在第6行的“ cin”上放置任何内容,因为该指令已经执行了(!).为什么?因为还有些东西在流动中。正如我之前所说,流是在一个流,所以一切都必须尽快从它删除。当计算机看到指令在 > 年龄时,可能性就出现了;

Computer doesn't know that you created a variable that stores age of somebody (line 4). 'age' is merely a label. For computer 'age' could be as well called: 'afsfasgfsagasggas' and it would be the same. For him it's just a variable that he will try to assign "Wlodarczyk" to because you ordered/instructed computer to do so in line (6).

这样做是不对的,但是,嘿,是你做的! 这是你的错! 好吧,也许用户,但仍然..。


All right all right. But how to fix it?!

在我们修正这个例子之前,让我们先试着玩一下,学习一些更有趣的东西: -)

我更喜欢用我们理解事物的方法。在不知情的情况下修理东西并不能带来满足感,你不觉得吗?:)

string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate(); //new line is here :-)

在调用上面的代码之后,您将注意到您的流(cin)的状态等于4(第7行)。这意味着它的内部状态不再等于 Goodbit。有些事情搞砸了。很明显,不是吗?您尝试将字符串类型值(“ Wlodarczyk”)赋给 int 类型变量‘ age’。类型不匹配。是时候告诉他们出事了。计算机通过改变流的内部状态来实现。这就像是: “你他妈的搞砸了,伙计,请修好我。我‘好心’地通知你; ——”

您不能再使用“ cin”(stream)了。卡住了。就像你把大木头放在水流上。你必须在使用它之前修好它。数据(水)不能从该流(辛) ,因为木材(内部状态)不允许你这样做。

哦,所以如果有一个障碍(木材) ,我们可以只是移除它使用的工具,这样做呢?

太棒了!

内部的状态设置为4就像一个警报器,是嚎叫和制造噪音。

Clear 将状态清除回正常状态(goodbit)。就好像你过来把警报关了。你只是推迟了。你知道发生了什么事,所以你说: “不要再吵了,我知道已经出事了,闭嘴(清楚)”。

好的,我们这样做! 我们使用 cin.clear ()。

使用“ Arkadiusz Wlodarczyk”作为第一个输入调用下面的代码:

string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;
cin.clear(); //new line is here :-)
cout << cin.rdstate()<< endl;  //new line is here :-)

我们可以肯定地看到,在执行以上代码后,状态等于 Goodbit。

很好,问题解决了?

Invoke below code using "Arkadiusz Wlodarczyk" as first input:

string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;;
cin.clear();
cout << cin.rdstate() << endl;
cin >> age;//new line is here :-)

Even tho the state is set to goodbit after line 9 the user is not asked for "age". The program stops.

为什么? !

哦,伙计... 你刚刚拉响了警报,那水里的木头怎么办?回到我们讨论“ Wlodarczyk”如何消失的短信 * 。

你得把“ Wlodarczyk”那块木头从河里弄出来。关掉警报器根本解决不了问题。你刚让它沉默,你就觉得问题解决了?;)

因此,是时候使用另一种工具了:

忽略可以比喻为一个特殊的卡车与绳索来,并删除木材原木,使溪流卡住。它清除了程序用户创建的问题。

那我们能不能在警报响之前就用上它?

是的:

string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;

在第七行发出噪音之前“ Wlodarczyk”会被移除。

10000和 n 是什么?

它说删除10000个字符(以防万一) ,直到满足 n’(ENTER)。顺便说一下,使用 numeric _ limit 可以做得更好,但这不是这个问题的答案。


So the main cause of problem is gone before noise was made...

那我们为什么需要“清除”?

What if someone had asked for 'give me your age' question in line 6 for example: "twenty years old" instead of writing 20?

类型又不匹配了。计算机尝试将字符串赋给 int。警报响了。你甚至没有机会对这种情况做出反应。Cin 这种情况下忽略也没用。

因此,我们必须使用 clear 来应对这种情况:

string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow

但是你是否应该“以防万一”清除这个州?

当然没有。

如果出现错误(cin > > age;) ,指令将通过返回 false 通知您。

因此,我们可以使用 If判断语句来检查用户是否在流上输入了错误的类型

int age;
if (cin >> age) //it's gonna return false if types doesn't match
cout << "You put integer";
else
cout << "You bad boy! it was supposed to be int";

All right so we can fix our initial problem like for example that:

string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow


int age;
cout << "Give me your age:" << endl;
if (cin >> age)
cout << "Your age is equal to:" << endl;
else
{
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
cout << "Give me your age name as string I dare you";
cin >> age;
}

当然,这可以通过例如使用 loop while 来改进。

BONUS:

你可能会好奇。如果我想从用户那里得到同一行中的名字和姓怎么办?如果 cin 将每个由“空间”分隔的值解释为不同的变量,那么使用 cin 是否可能?

当然,你可以有两种方式:

1)

string name, surname;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin >> surname;


cout << "Hello, " << name << " " << surname << endl;

2) or by using getline function.

getline(cin, nameOfStringVariable);

and that's how to do it:

string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);


cout << "Hello, " << nameAndSurname << endl;

The second option might backfire you in case you use it after you use 'cin' before the getline.

我们来看看:

答)

int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endl;


string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);


cout << "Hello, " << nameAndSurname << endl;

如果你把“20”作为年龄,你就不会被问到名字和姓氏。

But if you do it that way:

B)

string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);


cout << "Hello, " << nameAndSurname << endl;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endll

everything is fine.

什么? !

每次你在输入(流)中输入一些东西,你都会在结尾留下一个白色的字符,那就是 ENTER (’n’) ,你必须以某种方式输入值到控制台。因此,如果数据来自用户,就必须这样做。

B) cin 的特点是它忽略空格,所以当您从 cin 中读取信息时,换行符‘ n’并不重要。它被忽略了。

A) getline 函数获取整行的换行字符(’n’) ,当换行字符是第一个字符时,getline 函数获取’n’,这就是要获取的全部内容。您可以提取第3行中将“20”放在流上的用户留在流上的换行符。

因此,为了修复这个问题,必须始终调用 cin.Ignore () ; 如果在程序中使用 getline () ,那么每次使用 cin 获取任何值时。

因此,正确的代码应该是:

int age;
cout << "Give me your age:" <<endl;
cin >> age;
cin.ignore(); // it ignores just enter without arguments being sent. it's same as cin.ignore(1, '\n')
cout << "Your age is" << age << endl;




string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);


cout << "Hello, " << nameAndSurname << endl;

我希望你知道溪流更清晰。

请让我安静! : -)