【问题标题】:Is there a way I can check if user input is a number?有没有办法检查用户输入是否是数字?
【发布时间】:2020-04-03 20:56:00
【问题描述】:

我做了一个用户需要猜数字的游戏,

号码是用rand函数生成的。

如果用户输入了无效的数字或字符,打印错误信息。

我的问题是cin.fail()对我来说效果不佳,例如,当我输入一个字符作为输入时,我的程序总是打印“太低!”,可能是因为它计算了字符的值(@ 987654321@).

有什么建议吗?

我的代码:

void Game()
{
    srand(time(0));

    int iGuess;
    const unsigned int iNum = (rand() % 1000 + 1);

    Start:
    system("cls");

    cout << "\n Guess the Num: "; cin >> iGuess;
    if (iGuess == iNum) {
        system("color A");
        cout << "\n\n Good Job! You Won!";
        exit(0);
    }
    if (iGuess > iNum) {
        cout << "\n\n Too High!";
        Sleep(3000);
        goto Start;
    }
    if (iGuess < iNum) {
        cout << "\n\n Too Low!";
        Sleep(3000);
        goto Start;
    }
    if (cin.fail()) {
        cout << "Input has failed! & Error Code: " << GetLastError();
        Sleep(3000);
        goto Start;
    }
}

【问题讨论】:

  • 尝试使用该输入检查用户输入是否在之前失败。编辑:您还需要在用户重试之前清除错误状态:How to clear cin Buffer in c++
  • 您可以将用户输入作为字符串,然后使用std::strtol() 将其转换为数字。您可以检查第二个参数中的返回值,以查看是否存在转换错误(即字符串是否不是有效数字)。
  • 检查cin.fail()应该是输入后的第一个。如果输入失败,iGuess 中的值将无用。
  • 而且,如果输入失败,您必须重置它并消耗垃圾。你可以看看这个:SO: C++ Beginner Infinite Loop When Input Wrong Data Type and Help Evaluate My Code - 它是一个float 值,但原理是相似的。
  • 我想知道还没有人提到goto Start; 的可怕用法... ;-)

标签: c++


【解决方案1】:

首先您可以检查 ,布尔转换 (explicit operator bool() const) 是否等同于 !failed()(请参阅 https://en.cppreference.com/w/cpp/io/basic_ios/operator_bool)。

这允许你写:

void Game()
{
  srand(time(0));

  int iGuess;
  const unsigned int iNum = (rand() % 1000 + 1);

Start:
  system("cls");

  cout << "\n Guess the Num: ";
  if (cin >> iGuess)
  {
    if (iGuess == iNum)
    {
      system("color A");
      cout << "\n\n Good Job! You Won!";
      exit(0);
    }
    if (iGuess > iNum)
    {
      cout << "\n\n Too High!";
      Sleep(3000);
      goto Start;
    }
    if (iGuess < iNum)
    {
      cout << "\n\n Too Low!";
      Sleep(3000);
      goto Start;
    }
  }
  else
  {
    cin.clear();                        // clear error flags
    cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // empty buffer 
    assert(cin);                        // check that we are still in a good state

    cout << "Input has failed! & Error Code: " << GetLastError();
    Sleep(3000);
    goto Start;
  }
}

如果发生错误,请务必不要忘记以下步骤:

清除错误标志:

cin.clear(); 

删除之前存储在缓冲区中的所有数据(并且不能解释为整数)

cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 

检查我们是否仍然处于良好状态(防御性编程,可能发生了另一个错误)

assert(cin); 

更新: 使用ignore当然更好,我的第一个版本是

while (cin.get() != '\n') continue; 

我的更新是:

cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 

【讨论】:

    【解决方案2】:

    使用std::string_viewstd::isdigit() 解析输入字符串的最简单方法。

    char str[] = "12abc12"; 
    
    int alphabet = 0, number = 0, i; 
    for (i=0; str[i]!= '\0'; i++) 
    { 
        // check for alphabets 
        if (isalpha(str[i]) != 0) 
            alphabet++; 
    
        // check for decimal digits 
        else if (isdigit(str[i]) != 0) 
            number++; 
    } 
    

    https://www.geeksforgeeks.org/isalpha-isdigit-functions-c-example/

    【讨论】:

    • ints 的流操作符已经完成了这项工作。
    • 你能帮我提供更多细节吗?
    • 谢谢;如果输入就像一个组合,例如47b,这是无效的,应该被拒绝。
    【解决方案3】:

    我建议使用 do while 格式来获取您的输入。

    #include <stdlib.h>
    #include <time.h>
    #include <iostream>
    #ifdef _WIN32
    #include <windows.h>
    
    void sleep(unsigned milliseconds)
    {
        Sleep(milliseconds);
    }
    #else
    #include <unistd.h>
    
    void sleep(unsigned milliseconds)
    {
        usleep(milliseconds * 1000); // takes microseconds
    }
    #endif
    using namespace std;
    
    int main()
    {
        srand(time(0));
    
        int iGuess;
        const unsigned int iNum = (rand() % 1000 + 1);
    
    Start:
        system("cls");
    
        do
        {       
            if (!std::cin)
            {
                std::cin.clear();
                std::cin.ignore(10000, '\n');
                std::cout << "\nFailed input";
            }
            std::cout << "\n Guess the Num: ";
        } while (!(std::cin >> iGuess));
    
    
        if (iGuess == iNum) {
            system("color A");
            cout << "\n\n Good Job! You Won!";
            exit(0);
        }
        if (iGuess > iNum) {
            cout << "\n\n Too High!";
            Sleep(3000);
            goto Start;
        }
        if (iGuess < iNum) {
            cout << "\n\n Too Low!";
            Sleep(3000);
            goto Start;
        }
    }
    

    【讨论】:

    • 使用std::numeric_limits&lt;std::streamsize&gt;::max() 来保证您清除整个缓冲区,而不是任意数字。
    • 弗朗索瓦是正确的,最好使用numeric_limits。
    • 第一个输入无论如何都不会被忽略吗?这需要进一步微调......
    • 我更新了我的帖子以包含我已经测试过并且正在运行的代码。我还更新了代码以包含有关如何在失败时打印消息的示例。
    猜你喜欢
    • 1970-01-01
    • 2010-09-06
    • 2014-10-14
    • 1970-01-01
    • 2011-01-30
    • 2021-12-22
    • 2020-11-25
    • 2014-12-22
    • 2021-06-06
    相关资源
    最近更新 更多