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

发布于 2024-10-09 00:04:22 字数 537 浏览 3 评论 0原文

我正在做一个控制台应用程序,我将一个整数传递给应用程序,它工作正常,但如果我传递一个字母,它就会变得疯狂,

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() 但得到相同的结果。谢谢

I'm doing a console app, I'm passing an integer to the app and it works ok, but if I pass a letter, it goes crazy,

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;
}

I tried to use isdigit() but I get the same result. Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

演出会有结束 2024-10-16 00:04:22

执行cin>>后提取时,您想检查 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 错误处理中出现轻微错误。已更正,现在应该可以工作了。 :)

After performing cin >> extraction, you want to check if the cin stream is still good or not. If you expect cin to extract a number but it gets something else instead, eg. like a letter, then the stream will be set to a bad state and that's why you see it 'going crazy'.

What you have to do is after input, check if cin is still good. If it's in a bad state, you need to clear its flags and then remove out any of the junk data in the stream. If you don't, then subsequent uses of cin will simply fail to function.

Taking your code snippet for example, you can change it to something like this:

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);

Edit: whoops minor error in the cin error handling. Corrected and should be working now. :)

他不在意 2024-10-16 00:04:22

问题是调用 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' );

The problem is that the call std::cin >> opt is failing to parse the character and returns immediatly (without consuming the buffer), then it finds the same contents and fail....

You should check the result of the operation and react to it. One possibility would be checking the fail bit (std::cin.fail()) and failing the whole operation or consuming parts of the buffer (maybe a a single character, maybe more, depending on how you want the application to behave).

The simplest thing would probably be not reading into a number, but rather a character, and then comparing with the expected character:

char opt = 0;
do {
   // prompt user for input
   if (! (std::cin >> opt) ) {
      // io error, report and bail out
      break;
   }
} while ( opt != '0' && opt != '1' );
情归归情 2024-10-16 00:04:22

直接读取数字是
有问题

如果 std::cin 与输入一起出现
无法处理,std::cin 进入
“失败”状态 无法输入
进程留在输入流上。

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

读取的例程
直接输入数字应该:

  1. 阅读
    数量

  2. 检查输入是否正确
    流仍然有效

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

    1. 致电
      std::cin.clear() 获取流
      摆脱“失败”状态。
    2. 从以下位置删除
      导致的输入流
      问题:std::cin.ignore(...)
    3. 获取
      如果合适的话再次输入或
      否则处理错误

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

Reading in numbers directly is
problematic

If std::cin is presented with input it
cannot process, std::cin goes into a
"fail" state The input it cannot
process is left on the input stream.

All input will be ignored by std::cin
until the "fail" state is cleared:
std::cin.clear()

A routine that reads
a number directly should:

  1. Read in the
    number

  2. Check to see that the input
    stream is still valid

  3. If the input
    stream is not good (!std::cin)

    1. Call
      std::cin.clear() to take the stream
      out of the "fail" state.
    2. Remove from
      the stream the input that caused the
      problem: std::cin.ignore(...)
    3. Get the
      input again if appropriate or
      otherwise handle the error

more info here: http://www.augustcouncil.com/~tgibson/tutorial/iotips.html

べ繥欢鉨o。 2024-10-16 00:04:22

当您插入字母时,会发生这种情况:

  1. operator>> 从流中提取字符并尝试将它们转换为数字;
  2. 它在转换中失败,因此它将流状态设置为 ios::failbit 并返回; opt 可能未受影响(标准将这些东西委托给语言环境库,这是我从未真正理解的 C++ 区域 - 对于足够勇敢的人来说,它位于 §22.2.2.1.2);
  3. 因为它返回了并且(可能)opt 保持原样,所以循环继续;
  4. 当执行返回到std::cin>>时opt;operator>> 看到状态仍然是 ios::failbit,因此它甚至不会尝试提取任何内容;
  5. goto 3.

要解决该问题,您应该清除错误状态并从输入缓冲区中删除“错误”字符。由于您可能不想将所有代码添加到每个 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

When you insert a letter this happens:

  1. operator>> extracts characters from the stream and try to convert them to a number;
  2. it fails in the conversion, so it sets the stream state to ios::failbit and returns; opt probably is untouched (the standard delegates this stuff to the locale library, which is a zone of C++ that I never really understood - for the brave enough, it's at §22.2.2.1.2);
  3. since it returned and (probably) opt is left as it is, the loop continues;
  4. when the execution returns to std::cin >> opt;, operator>> sees that the state is still ios::failbit, so it doesn't even try to extract anything;
  5. goto 3.

To fix the problem, you should clean the error state and remove the "wrong" characters from the input buffer. Since you probably don't want to add all that code to every cin>>, it's useful to create a function to deal with this common problem; personally, I created this little header (AcquireInput.hpp) that has proven useful many times:

#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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文