读入数字型变量时,输入非数字的后果
在看C4P的时候书上提到,有这么一段代码:
char ch;
cin >> ch;
while(ch != '#')
{
...
cin >> ch;
}
如果在循环中cin到一个char类型变量中,会使程序陷入死循环。当时就在想,如果拿不到合法的数据的话,不是应该丢掉非法输入,等待下一个合法输入的到来么。后来在网上查找相关信息后,发现C和C++对于这一异常情况有着不同的处理思路。
下文假设有如下定义:int var;。
在C语言中,使用scanf("%d", &var);从输入流读取一个整型数据(浮点型同理)。在这种情况下,如果读取到的数据无法解析为对应类型的有效值的话,scanf的返回值为0,表示读入整型数据失败。在这种情况下,scanf不会修改对应的目标变量,下次scanf调用从当前失败的位置继续开始。
在C++中,使用的语句是cin >> var;。如果读取的数据无法转换为var的类型(这里是int)的话,根据C++规范版本,对var有两种不同的处理方式:在C++11之前,var的值不变;C++11及以后,var置零。同时,从此往后的cin的failbit置1,所有对cin的调用均失败返回,且不修改对应变量值。要解决这种情况,需要调用cin.clear();方法重置cin的异常状态,然后才可以继续正常使用cin。
从此可以得知,上述代码在C++11的条件下的确会产生无限循环的问题:第一次调用失败时,ch置零,不等于#,循环继续;而后续由于cin处于fail状态,不再产生任何有效的数据读取,使得ch始终维持为0,进而导致无限循环的产生。可以用如下程序验证:
#include <iostream>
using namespace std;
int i = -1;
char ch = '?';
void cpp()
{
cin >> i;
cout << i << endl;
cin >> ch;
cout << ch << endl;
}
void c()
{
scanf("%d", &i);
printf("%d\n", i);
scanf("%c", &ch);
printf("%c\n", ch);
}
int main()
{
// or cpp() to test the c++-style input
c();
return 0;
}