读入数字型变量时,输入非数字的后果
在看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;
}