0

下面的代码应该检查每个输入一次,并在输入不是数字时显示“不是数字”。

int input;
while (1 == 1){
    cout << "Enter a number: ";
    try{
        cin.exceptions(istream::failbit);
        cin >> input;
    }catch(ios::failure){
        cout << "Not a number\n";
        input = 0;
    }
}

问题在于,当调用 catch 时(当它不是数字时),它会无休止地显示“无效数字”,就像 while() 循环执行了多次但没有要求任何新输入一样。

4

3 回答 3

3

while(true)or while(1)[or for(;;)] 是制作“永远循环”的惯用方式。

您需要“清理”cin流中不可接受的输入。典型的方法是调用cin.ignore(1000, '\n');它将忽略所有输入,直到下一个换行符[最多 1000 个字符 - 您可以选择更大的数字,但通常 1000 是“足以到达换行符”。

您几乎可以肯定(感谢 Potatoswatter)需要调用cin.clear();输入以删除failed状态,以便下一个输入可以成功。[并且cin.ignore()是进一步的输入,因此需要在此之前进行-只是为了清楚]。

于 2013-08-02T23:11:44.420 回答
1

尽管您未能将字符从流中提取到 中int,但这些字符仍保留在流中,以便您可以尝试将它们提取为其他内容。

要完全跳过它们,std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');请在您的catch块内运行。

然后,用户接下来输入的内容将是流中的第一件事。也许这将是一个数字,所以你下次尝试提取到一个int成功。

于 2013-08-02T23:16:37.487 回答
0

嗯,是的。您的 try-catch 语句在循环内。所以你尝试一些东西,它失败并抛出一个异常,然后你捕捉到异常,你永远不会退出或从循环中返回,所以你再次做同样的事情。

但是由于您的输入第一次没有被处理(而是抛出异常),所以第二次、第三次或任何时候都不会处理它。

要前进,通过忽略输入直到下一个空格来处理异常:

int input;
while (1 == 1){
    cout << "Enter a number: ";
    try{
        cin.exceptions(istream::failbit);
        cin >> input;
    }catch(ios::failure){
        cout << "Not a number\n";
        input = 0;
        //the line below ignores all characters in cin until the space (' ')
        //(up to 256 characters are ignored, make this number as large as necessary
        cin.ignore(256, ' ');  
    }
}

顺便说一句,作为一般规则:异常应该是真正异常的东西,特别是因为处理异常存在开销。关于无效的用户输入是否异常存在争论。

作为替代方案,您可以创建一个更紧凑、同样正确的循环,而不会出现以下异常:

int input;
while (true){  //outer while loop that repeats forever. Same as "while(1 == 1)"
    cout << "Enter a number: ";
    //The following loop just keeps repeating until a valid value is entered.
    //The condition (cin >> input) is false if e.g. the value is a character,
    //or it is too long to fit inside an int.
    while(!(cin >> input)) { 
      cout << "Not a number" << endl;
      input = 0;
    }
}
于 2013-08-02T23:07:51.060 回答