【问题标题】:How to not accept a float when inputting an int in c++在 C++ 中输入 int 时如何不接受浮点数
【发布时间】:2021-01-22 12:59:40
【问题描述】:

我目前正在学校尝试编写一个程序,该程序涉及用于掷骰子的随机数生成器。我已经成功编写了代码,但我正在尝试改进它,以便用户可以选择骰子的大小和用户尝试滚动的数字。

我已经编写了执行此操作的代码,并且我还添加了代码,如果错误的值(即不是提供的骰子大小之一或试图掷骰子范围之外的数字)或输入类型(即 var 而不是 int)。但是,如果输入了浮点数,并且浮点左侧的数字在正确的值范围内,则它正在使用该数字。

例如:

    int size = 0;
    cout << "Please choose the size of the dice to roll (6, 12 or 20): ";
    cin >> size;

    while (size != 6 && size != 12 && size != 20 || !cin)
    {
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cout << "Invalid number entered. Choose the size of the dice to roll (6, 12 or 20): ";
        cin >> size;
    }

如果输入了任何不是 6、12 或 20 的字母或任何数字,但如果输入 20.125(或 6.- 12.- 或 20.- 的任何浮点数,这将正确地要求重复输入) 输入它将获取数字并移动到下一位代码。如果我输入一个有效数字后跟字母(即 6f),也会发生这种情况。

我尝试将while循环的条件修改为:

    while (size != 6 && size != 12 && size != 20 || !(cin >> size))
    {
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cout << "Invalid number entered. Choose the size of the dice to roll (6, 12 or 20): ";
        cin >> size;
    }

这解决了问题,如果我输入 12.5 或 20R 等,它会要求我输入另一个输入,但是当我输入正确的输入(6、12 或 20)时,它只会将我带到调试器中的新行无需移动到下一行代码。如果我然后再次输入正确的输入,它会读取它并将我带到下一行代码。

我不太明白为什么一个错误可以 99% 以我想要的方式工作,而另一个修复了该错误但又给了我另一个错误。

提前致谢,非常感谢任何建议指导!

【问题讨论】:

  • 你可以读成一个字符串并尝试convert the string to an integer,然后检查整个字符串是否被转换。
  • 无关:如果cin 关闭,则循环将永远继续。
  • 不幸的是,cin 完全没用。我推荐@Someprogrammerdude 的建议。

标签: c++ validation c++11 input while-loop


【解决方案1】:
template<typename T>
T typed_read_line(const std::string& prompt)
{
   T result{};
   std::string l;
   std::cout << prompt << ":";
   while (std::getline(std::cin, l)) {
      std::istringstream line{l};
      line >> result >> std::ws;
      if (line.eof()) break;
      //line contains more then expected
      std::cout << "Again: " << prompt << ":"; 
   }
   return result;
}

https://godbolt.org/z/dfYKe3

或带有extra validationv3 的版本。

【讨论】:

    【解决方案2】:

    cin &gt;&gt; some_int_variable 将逐个字符地解释输入,直到它不再作为 int 有意义。例如,当它遇到.f 时,cin 就读完了那个int。

    如果您想要不同的行为,则必须自己实现。具体来说,如何停止处理一个输入并开始处理下一个输入?

    cin &gt;&gt; some_int_variable 将在它不再有效时停止,cin &gt;&gt; some_std_string_variable 将在遇到空白字符(包括新行)时停止。你的问题呢?您想如何将一个输入与另一个输入分开?

    如果留白是一种明智的做法,您可以这样做:

    std::string word;
    std::cin >> word;
    
    int value;
    bool error = false;
    try {
        size_t pos;
        value = std::stoi(word, &pos);
        // Was the full string used to build the int?
        if(pos != word.size()) error = true;
    } catch(std::logic_error&) {
        error = true;
    }
    
    if(error) { /* something went wrong */ }
    

    请参阅docs for std::stoi()

    【讨论】:

    • 嗨,Ivella,感谢您的建议,您所说的很有道理(即使代码没有,我对此也很陌生,所以我宁愿省略该功能而不是提交我不理解的代码。)但是,有一个问题,当我在 while 条件下使用 !(cin &gt;&gt; diceSize) 而不仅仅是 !cin 时,它会执行我想要的操作,因为它不会将 12.4 或 6f 等读取为int 并且会正确地告诉我再次输入一个数字,但是如果我输入一个正确的值(6 12 或 20),它似乎不会注册它们。
    • 因为cin &gt;&gt; diceSize 尝试再次读取输入。如果下一个字符是数字,它会起作用并覆盖diceSize 的先前值,因此您会丢失它。如果下一个字符是.R,则会失败,并且您会收到错误消息。另外,请参阅:stackoverflow.com/questions/5605125/…
    【解决方案3】:

    您可以读取一个浮点数,将其分配给一个整数变量,然后比较两者。大致如下:

    int integerSize;
    float floatSize;
    cin >> floatSize;
    integerSize = floatSize; //Your program will perform a cast from float to integer, it will essentially truncate whatever appears after the floating point.
    if (integerSize != floatSize) //Your program will now perform a cast from integer to float in order to compare the two, but if floatSize was not a whole number, this comparison should return false.
    {
      //code to ask for another value
    }
    

    话虽如此,浮点数(以及双精度数和长双精度数)确实会遇到舍入错误,因此正如另一位用户建议的那样,最安全的选择是读取字符串并自己解析它,或者使用像 std::stoi() 这样的内置函数(仅适用于整数)和std::stof()(适用于浮点数)。

    【讨论】:

    • 这不会修复像 6f 这样包含有效数字和一些字符的输入的行为。
    猜你喜欢
    • 1970-01-01
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-31
    • 1970-01-01
    相关资源
    最近更新 更多