【问题标题】:How to check for integer range?如何检查整数范围?
【发布时间】:2017-03-05 09:01:23
【问题描述】:

我有这个代码,但是当我输入一个超过整数值的值时它会打印垃圾。我实际上有 if 条件来检查范围。如何让它发挥作用?我知道这对你来说很容易。我只是在 C++ 中忘记了一些东西,我没有时间。

#include <iostream>
#include <typeinfo>
#include<cfloat>
#include<climits>

using namespace std;

int    g1, g2;
string text  = " year";
string text2 = " age";

int main() {
  g1 = 2100000000000000000000000;
  g2 = 16;

  if (g1 < INT_MIN || g1 > INT_MAX) {
    std::cout << "Please enter an integer";
  } else {
    std::cout << g1 << text;
    std::cout << g2 << text2;
  }

  return 0;
}

【问题讨论】:

  • 您正在检查int 是否小于INT_MIN。怎么可能?
  • Jou 可以尝试解析为整数。如果返回错误,则不是整数,因为它包含无效字符,或者大于INT_MAX 或小于INT_MIN
  • 这闻起来像XY problem。您真正想要达到什么目的?
  • 打开编译器警告并使用足够高的级别来获得类似warning: overflow in implicit constant conversion

标签: c++


【解决方案1】:

因为 C++ 故意模糊了基本类型(如 int)的最小和最大大小,所以像 2100000000000000000000000 这样的大整数文字很危险地依赖于平台。

您的程序甚至可能是格式错误的,因此根本无法编译。幸运的是,检查用户输入与整数文字没有任何关系。前者发生在运行时,后者是编译时方面。

这意味着您的示例代码是一个不切实际的场景。在实际程序中,g1 的值不是是编译时常量,而是用户输入的数字。

一个非常好的做法是先让用户用std::getline将数字输入到std::string,然后用std::stoi将字符串转换成int

如果您遵循这种做法,则所有错误检查都由标准库执行,您根本不必使用 INT_MININT_MAX 或它们的 C++ 对应项 std::numeric_limits&lt;int&gt;::min()std::numeric_limits&lt;int&gt;::max()

例子:

#include <iostream>
#include <string>

auto const text  = " year";
auto const text2 = " age";

int main() {
  try {
    std::string input;

    std::getline(std::cin, input);
    auto const g1 = std::stoi(input);

    std::getline(std::cin, input);
    auto const g2 = std::stoi(input);

    std::cout << g1 << text;
    std::cout << g2 << text2;
    std::cout << '\n';

  } catch (std::out_of_range const&) {
    std::cout << "Please enter an integer\n";
  }
}

很棒的是,这也将检测其他种错误的用户输入,例如当用户输入字母而不是数字时。在这段示例代码中扩展错误处理以捕获其他类型的异常留给读者作为练习。

【讨论】:

  • 再好不过了。这是一个很好的例子,如何以最小的方式获得价值,尽管它没有暴露 stoi() 使用的机制,它可以解决问题的问题(我们可能隐藏了一个 X-Y)。有时可能想要创建自己的函数,添加自定义操作或错误处理,或者使用无异常代码
  • @Swift:事实上,我会亲自将std::stoi 包装在我自己的函数中,并使用异常以外的东西来报告错误,因为错误的用户输入并不是真正的异常。可能返回一个元组或结构 std::optional&lt;int&gt; 和一个错误代码。
【解决方案2】:

在 C++ 中,您应该使用 std::numeric_limits(来自 &lt;limits&gt;)。以 C 开头的标头 &lt;climits&gt; 的名称表明它是旧的 C 标头,为了兼容性而保留(以前的 limits.h)。您忘记了表达式中的括号,它将被错误地评估。字面量对于 int 来说太大了。值实际上不能超出绑定类型的界限

http://en.cppreference.com/w/cpp/types/numeric_limits

#include <iostream>
#include <typeinfo>
#include<limits>

long long g1, g2;

int main() 
{
  //...

  if ((g1 > std::numeric_limits<int>::lowest()) 
       || (g1 < std::numeric_limits<int>::max())) 
  {
       //...
  } 

  return 0;
}

如果用户做错了什么,您必须以重置输入的方式处理来自 cin 的输入。要实际(关闭蠕虫罐)检查范围,您需要更大的(蠕虫罐)存储空间。考虑这个函数:

int  getInt()
{
    while (1) // Loop until user enters a valid input
    {
        std::cout << "Enter an int value: ";
        long long x;  // if we'll use char, cin would assume it is character
        // other integral types are fine
        std::cin >> x;

        if (std::cin.fail()) // has a previous extraction failed?
        {
            // yep, so let's handle the failure, or next >> will try parse same input
            std::cout << "Invalid input from user.\n";
            std::cin.clear(); // put us back in 'normal' operation mode
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); // and remove the bad input
        }
        // Thechnically you may do only the above part, but then you can't distingusih invalid format from out of range
        else if(( x  > std::numeric_limits<int>::max()) ||
            ( x  < std::numeric_limits<int>::min()))
        {
            std::cout << "Invalid value.\n";
        }
        else // nope, so return our good x
            return x;
    }
}

如果 istream 未能将输入解析为所需类型,则缓冲区的剩余内容将保持不变,直到您将其清除或您请求将导致成功的操作。例如,您可以检查用户是否输入了浮点数.. 或者他是否输入了停止程序的命令。

【讨论】:

    【解决方案3】:

    您想要做的事情真的很难检查。就像检查您是否将负数保存到无符号整数中一样。一旦将其保存在那里,信息就会丢失并且值会损坏,因为存储在该变量中的信息表示不同。

    我不确定如果你尝试保存一个大于变量空间的值会发生什么,但最好的选择还是将它作为字符串加载并用 std::stoi() 解析它,这会给你错误如果值超出 int 范围。

    【讨论】:

    • 检查用户输入总是一件棘手的事情,你必须假设用户错了,可能是错的,以及他们如何可能错了。超出的范围可能看起来是一个边缘案例(小约翰尼掉落表会得到你xkcd.com/327)。流确实有错误状态,在 >> operator 的文档中描述
    【解决方案4】:

    如果您的目标是检查输入数字是否在整数范围内?然后您可以将输入数字作为字符串,并使用字符串函数检查数字是否在范围内。这是一种实现。

    std::string inputNum = ""; //input number as string
    std::cin>>inputNum; //assuming you are going to input numbers only
    std::string maxNum = std::to_string(INT_MAX); //2147483647
    std::string minNum = std::to_string(INT_MIN); //-2147483648
    
    if(inputNum[0] == '-') //negative number
    {
        /* if num of digits are more than min Number's digit
         * then the number is already out of range 
         * if num of digits are equal then you would have 
         * to check whether it is less than the min number or not
         * all numbers with lesser number of digits are in the range
        */
        if(inputNum.length() > minNum.length()) 
            std::cout<<"Not an integer" << std::endl;
        else if(inputNum.length() == minNum.length())
            if(inputNum > minNum)
                std::cout<<"Not an integer" << std::endl;
            else
                std::cout<<"Integer" << std::endl;
        else
            std::cout<<"Integer" << std::endl;
    }
    
    else //positive number
    {
        if(inputNum.length() > maxNum.length())
            std::cout<<"Not an integer" << std::endl;
        else if(inputNum.length() == maxNum.length())
            if(inputNum > maxNum)
                std::cout<<"Not an integer" << std::endl;
            else
                std::cout<<"Integer" << std::endl;
        else
            std::cout<<"Integer" << std::endl;
    }
    

    【讨论】:

      【解决方案5】:

      只需检查输入是否成功:

      #include <iostream>
      
      
      int main()
      {
          int val;
          if (std::cin >> val)
              std::cout << "value is " << val << "\n";
          else
              std::cout << "value input failure\n";
      
          return 0;
      }
      

      Live on Coliru

      【讨论】:

        【解决方案6】:

        c++ 有头文件,对于你正在使用的实现,不同的数据类型有一些最小值和最大值。

        看那里。此外,你必须使用64位整数,看它是否小于最大值或大于最小值对于32位整数,然后你可以转换。

        【讨论】:

        • 它不像在 C++ 中“使用”一个 64 位类型那么简单,short、int、long 的大小只能保证至少是一定的大小。一个简单的“int”可能是至少包含 16 位的任何东西——它可能是 16、32、64 位甚至更大。有固定宽度的类型,但它们是可选的。而且您的回答并没有太大帮助“您需要做一些事情-但我不会给出我提到的标题或数据类型的名称”。
        猜你喜欢
        • 2011-06-29
        • 2011-09-21
        • 1970-01-01
        • 2011-03-31
        • 2016-01-28
        • 2013-02-11
        • 2011-05-01
        • 1970-01-01
        • 2011-06-08
        相关资源
        最近更新 更多