不要接受小数作为输入

时间:2014-05-20 17:58:25

标签: c++ error-checking

我必须编写一个程序,要求用户输入一个数字,如果输入为零,则打印输出为0,如果输入负数或正数,则打印出他们输入的数字负数或正数。我有它所以它不接受字母,逗号等。但我无法弄清楚如何让这个不接受小数?我有什么线索可以做到这一点?除cplusplus.com之外的任何具有良好c ++引用的好站点

#include <iostream>
#include <string>
#include <limits>
#include <cmath>
#include <iomanip>
#include <cstdlib>

using namespace std;

    int getInt()
    {
    int choice=0;
    while (!(cin >> choice))
        {
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(),'\n');
        cout << "Please input a valid integer: " << '\n';
        }
    return (choice);
    }

int print_zero()
{
 cout << "The number you entered is a zero. " << '\n';
 return 0;
}

int print_negative()
{
 cout << "You entered a negative number. " << '\n';
 return 0;
}

int print_positive()
{
    cout << "You entered a positive number. " << '\n';
    return 0;
}

int main ()
    {

    cout << "your number please:-" << '\n';
    int choice = getInt();

    if (choice == 0)
    {
        print_zero();
    }

    if (choice < 0)
    {
        print_negative();
    }

    if (choice > 0)
    {
        print_positive();
    }

cout << endl << "All done! Nice!!" << endl;

return 0;
}

2 个答案:

答案 0 :(得分:0)

一件相当容易的事情就是使用像

这样的东西
std::string line;
std::getline(std::cin, line);

size_t pos;
int x = 0;

try
{
  x = std::stoi(line, &pos);

  if (pos < line.length())
  {
    std::cout << "Warning, non-digit character " << line[pos] << " detected!\n"
    return;
  }
}
catch (std::exception&)
{
  std::cout << "That didn't look like an integer to me.\n";
  return;
}

getline从输入中获取所有文本,而不是仅仅停留在无法转换为您请求的格式的第一个字符(例如int)。它也为你摆脱了任何不方便的尾随\n

std::stoi执行从std::stringint的转换。阅读docs,如果你不小心,可以抛出异常!它返回pos中第一个未转换字符的位置。如果pos小于line的长度,则表示某处的某个地方不属于int

答案 1 :(得分:0)

除了上一个答案之外,您还可以选择创建自己的std::num_get<char>方面,以便将自定义输入解析无缝集成到IOStreams界面中。

如果您在读取整数时碰巧输入浮点文字,则流仍将尽可能多地解析字符,只要这些字符可用于您要提取的数据类型即可。当流找到流的结尾,空格字符或不符合该类型的格式要求的字符时,它才会停止读取。在我们的例子中,流将找到字符.,然后停止阅读。

结果是即使部分输入已被消耗,读取也被认为是成功的。然而,下一个读取将不成功,因为下一个字符是.,它在整数中不可用。

这是我们将用于定制我们的方面的信息。在读取输入后,我们只需检查下一个字符是否为小数点。如果,您有几个选项来报告错误:

你可以......

  • 输出错误消息

    输出错误消息对于控制台用户来说是最方便的,但不符合IOStream的设计。当检测到错误输入时,流不会向控制台输出错误消息,因此您的方面也不应该。

  • 抛出异常

    您可以抛出异常,但请注意它们不会在流外传播。这是因为默认情况下编程流不会抛出异常。相反,只要检测到异常,它们就会在流中设置std::ios_base::badbit。您必须在执行输入之前或之后在流上设置exceptions()掩码以捕获异常。另一个警告是,只有std::ios_base::failure从流中抛出,所以你只能抓住它。

  • 设置流状态

    设置流状态对于facet的用户最有意义,并且与IOStream的设计保持一致。这样,您就不必彻底改变使用流的方式。只需检查流状态下输入是否成功,就像使用普通方面一样自然而然。

设置流状态是我们将在以下代码中使用的方法:

#include <locale>

class num_get : public std::num_get<char>
{
public:
    // Override do_get which is a virtual function in the std::num_get<char>
    // base class. It is called by the public member function get() in the
    // implementation of std::basic_istream<charT>::operator>>(int&)

    // You might want to put this into a helper function and call it in
    // both the signed and unsigned overloads

    iter_type do_get( iter_type it, iter_type end, std::ios_base& str,
                      std::ios_base::iostate& err, long& v ) const
    {
        // Store a locale object for later use.
        std::locale loc(str.getloc());

        // delegate the extraction to the default base class function
        it = std::num_get<char>::do_get(it, end, str, err, v);

        // If the extraction succeeded, tell the user if positive or negative,
        // or zero
        if (!(err & std::ios_base::failbit))
        {
            if (v == 0)
                std::cout << "The number you entered is a zero.\n";
            std::cout << "You entered a " <<
                ((v >= 0) ? "positive" : "negative") << " number.\n";

            // Check whether the end has not been met (because of further
            // input that can't be used in a long). And if the first character
            // of that input is a decimal point (or '.' in en_US) then get
            // rid of that input for convenience, and set failbit

            if (it != end && *it == std::use_facet<std::numpunct<char>>(loc).decimal_point())
            {
                // We get rid of that input by calling the base class function
                // again which does all the necessary parsing.

                // Note that if you do not want to get rid of the invalid
                // floating point input, then simply remove these two lines.
                it = std::num_get<char>::do_get(++it, end, str, err, v);
                // Clear out v
                v = 0;

                // set failbit
                err |= std::ios_base::failbit;
            }
        }    
        return it;
    }
};

要在流中设置此方面,请将其安装到区域设置中,并且&#34; imbue&#34;该区域设置进入流。像这样:

// Create a new locale with std::num_get<char> facet replaced by our custom facet
std::locale new_locale(std::cin.getloc(), new num_get);
// Imbue this new locale into std::cin
std::cin.imbue(new_locale);

完成后无需删除构面。这由包含它的语言环境的析构函数处理。

如果你想获得不同的行为,应该在实际使用流之前完成区域设置。

Live Example