在看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置零。同时,从此往后的cinfailbit置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;
}

参考:
https://www.zhihu.com/question/54476315

标签: none

添加新评论