c ++验证数字并停止无限循环

时间:2010-12-27 15:20:21

标签: c++ integer

我正在做一个控制台应用程序,我正在将一个整数传递给应用程序并且工作正常,但如果我传递一封信,那就太疯狂了,

int opt=0;
std::cout<<"Pick lang:"<<'\n';
std::cout<<"1.[es-ES]:"<<'\n';
std::cout<<"2.[en-US]:"<<'\n';
std::cin >> opt;

while(opt<1 || opt>2)
{
    std::cout<<"\nERROR!"<<'\n';
    std::cout<<"Pick lang again:"<<'\n';
    std::cout<<"1.[es-ES]:"<<'\n';
    std::cout<<"2.[en-US]:"<<'\n';
    std::cin >> opt;
}

我尝试使用isdigit()但我得到了相同的结果。谢谢

4 个答案:

答案 0 :(得分:7)

执行cin&gt;&gt;之后提取,你想检查cin流是否仍然是好的。如果你希望cin提取一个数字,但它会得到其他东西,例如。就像一封信,然后流将被设置为一个糟糕的状态,这就是为什么你看到它“变得疯狂”。

你要做的就是在输入之后,检查cin是否还是好的。如果它处于错误状态,则需要清除其标志,然后删除流中的任何垃圾数据。如果不这样做,那么后续使用cin将无法正常运行。

以您的代码段为例,您可以将其更改为以下内容:

int opt = 0;
bool inputGood = false;

do
{
    std::cout << "Pick lang again:" << '\n';
    std::cout << "1.[es-ES]:" << '\n';
    std::cout << "2.[en-US]:" << '\n';
    inputGood = std::cin >> opt;
    if(!inputGood)
    {  
      std::cout << "\nERROR! Invalid choice." << '\n';
      cin.clear();
      while( cin.get() != '\n' );
    }
}while(!inputGood || opt < 1 || opt > 2);

编辑:在cin错误处理中发出轻微错误。已更正,现在应该正常工作。 :)

答案 1 :(得分:2)

问题是调用std::cin >> opt无法解析字符并立即返回(不使用缓冲区),然后它找到相同的内容并失败....

您应该检查操作的结果并对其作出反应。一种可能性是检查失败位(std::cin.fail())并使整个操作失败或消耗部分缓冲区(可能是单个字符,可能更多,具体取决于您希望应用程序的行为方式)。

最简单的事情可能不是读取数字,而是读取字符,然后与预期字符进行比较:

char opt = 0;
do {
   // prompt user for input
   if (! (std::cin >> opt) ) {
      // io error, report and bail out
      break;
   }
} while ( opt != '0' && opt != '1' );

答案 2 :(得分:1)

当您插入一封信时会发生这种情况:

  1. operator>>从流中提取字符并尝试将其转换为数字;
  2. 它在转换中失败,因此它将流状态设置为ios::failbit并返回; opt可能没有被触及(标准将这些东西委托给语言环境库,这是一个我从未真正理解的C ++区域 - 对于勇敢的,它是在§22.2.2.1.2);
  3. 因为它返回并且(可能)opt保持原样,循环继续;
  4. 当执行返回std::cin >> opt;时,operator>>看到状态仍为ios::failbit,因此它甚至不会尝试提取任何内容;
  5. 转到3。
  6. 要解决此问题,您应该清除错误状态并从输入缓冲区中删除“错误”字符。由于您可能不希望将所有代码添加到每个cin>>,因此创建一个处理此常见问题的函数非常有用;就个人而言,我创建了这个经常被证明有用的小标题(AcquireInput.hpp):

    #ifndef ACQUIREINPUT_HPP_INCLUDED
    #define ACQUIREINPUT_HPP_INCLUDED
    
    #include <iosfwd>
    #include <limits>
    #include <string>
    
        template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result)
        {
            do
            {
                Os<<Prompt.c_str();
                if(Is.fail())
                {
                    Is.clear();
                    Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
                }
                Is>>Result;
                if(Is.fail())
                    Os<<FailString.c_str();
            } while(Is.fail());
        }
    
        template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString)
        {
            InType temp;
            AcquireInput(Os,Is,Prompt,FailString,temp);
            return temp;
        }
    
        /* Usage example: 
    
            //1st overload
            int AnInteger;
            AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",AnInteger);
    
            //2nd overload (more convenient, in this case)
            int AnInteger=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");
        */
    
    #endif
    

答案 3 :(得分:1)

  

直接读数是   问题

     

如果std :: cin输入了它   无法处理,std :: cin进入了   “失败”状态输入它不能   进程留在输入流上。

     

std :: cin将忽略所有输入   直到“失败”状态被清除:   std :: cin.clear()

     

阅读的例程   一个数字直接应该:

     
      
  1. 阅读   编号

  2.   
  3. 检查输入   流仍然有效

  4.   
  5. 如果输入   流不好(!std :: cin)

         
        
    1. 呼叫   std :: cin.clear()取流   走出“失败”状态。
    2.   
    3. 从中移除   流引起的输入   问题:std :: cin.ignore(...)
    4.   
    5. 获取   如果适当,再次输入或   否则处理错误
    6.   
  6.   

此处有更多信息:http://www.augustcouncil.com/~tgibson/tutorial/iotips.html