【问题标题】:Validating Floating point in C++ without special libraries在没有特殊库的情况下验证 C++ 中的浮点
【发布时间】:2015-12-05 16:43:26
【问题描述】:

我知道以前有人问过这个问题,但答案并没有解决我的问题,所以我问这个问题

我有一个简单的程序来找到三个数字中最大的一个,它应该只接受浮点数。如果输入字符或字符串,则需要显示错误,用户需要再次输入。

我有一个函数来获取一个有效的浮动输入

float validInput()
    {
        float x;
        cout<< flush;
        cin >> x;
        while(cin.fail())
        {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(),'\n');
            cout << "Not a numeric value please enter again\n";
            cin >> x;
        }
        return x;
    }

所以我在 main 函数中使用 validInput 之类的输入

int main()
{
   float x = validInput();
   float y = validInput();
   float z = validInput();
   findGreatest(x,y,z);
   return 0;
}

此方法适用于大多数输入。当我输入一个数字后跟一个字符时它会失败,validInput 函数会奇怪地失败。在给出这样的输入时,它会显示错误消息 “不是数值,请再次输入”,但不接受另一个输入,而是将字符之前的数值视为输入并存储它。我的要求是忽略整个输入并要求新的输入

据我了解

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

不会忽略在输入开头输入的数字,而只会从流中清除字符,即使 cin.fail() 为真。

有没有办法解决这个问题? cin.ignore 可能需要不同的参数,但不确定。

提前致谢

来源: https://stackoverflow.com/a/16934374/5236575

PS:我不能使用任何特殊的库,比如 boost。该代码用于实现软件测试的测试用例,因此它需要正确处理任何类型的输入。

【问题讨论】:

    标签: c++ floating


    【解决方案1】:

    您可能想看看实际发生了什么,因为这种行为一点也不奇怪:当您在一行上输入一个浮点数后跟一个非数字时,浮点值被提取出来就好了。您的 validInput() 函数的失败案例是 not 命中 - 那个调用!但是,由于在再次调用该函数时,有些东西无法解析为浮点数再次第二次调用会触发失败!

    通过在validInput() 调用之间添加输出,您可以看到这确实是行为。通过这种方式,您可以判断哪些调用实际产生了错误。在没有错误的情况下存储值是预期的行为!

    您可以通过读取一行并验证您是否可以从该行读取并且该行后面除了空格之外什么都没有,可以确保该行不包含无效输入。例如:

    float validInput()
    {
        float x;
        // cout<< flush; There is *NO* reason to flush cout: it is flushed when using cin
        for (std::string line; std::getline(std::cin, line); ) {
            std::istringstream lin(line);
            if (lin >> x && (lin >> std::ws).eof()) {
                break;
            }
            cout << "Not a numeric value please enter again\n";
        }
        throw std::runtime_error("reached end of input before getting a valid value!");
        return x;
    }
    

    使用lin &gt;&gt; std::ws 会跳过此行上所有潜在的尾随空格(std::getline() 已删除换行符)。之后,应该使用流并设置eof() 标志,如果确实没有进一步的输入(这是eof() 的少数有效用途之一...)。

    【讨论】:

    • 很有意义。但是代码似乎不起作用,因为在按下输入时抛出 runtime_error 的任何数字输入后,在注释掉 throw std::runtime_error 行时它起作用,但在输入之前显示“不是数值请再次输入”。我猜这是因为在这个浮动输入之前还有其他输入。
    • return x; 应该可以取代break。
    • @vsoftco 将 break 替换为 return x; 修复了错误,谢谢。但是当这个函数是第一个被调用的时候工作正常。但是当我在调用此函数之前有其他 std::cin 语句时,它会打印 "Not a numeric value please enter again" 然后接受输入。
    【解决方案2】:

    std::cin 将从流中顺序读取,因此如果第一个字符表示有效数字,则认为没问题。如果您想确保您阅读的内容确实是只是一个数字(后面没有一些额外的字符),一种选择是使用std::getline 读取到std::string,然后将字符串转换为使用std::stof (C++11) 的浮点数。后者将指针作为第二个参数,该指针指向无法转换的第一个字符的位置。如果该位置小于字符串的长度,则您的行包含的不仅仅是数字,因此输入无效。

    例子:

    #include <iostream>
    
    int main()
    {
        float x;
        std::size_t pos;
        std::string str;
        while (std::getline(std::cin, str))
        {
            try
            {
                x = std::stof(str, &pos);
            }
            catch(...)
            {
                std::cout << "Not a numeric value please enter again\n";
                continue;
            }
            if(pos != str.length())
            {
                std::cout << "Not a numeric value please enter again\n";
                continue;
            }
            break;
        }
        std::cout << x;
    }
    

    【讨论】:

    • 输入字符时出现此错误terminate called after throwing an instance of 'std::invalid_argument' what(): stof Aborted (core dumped) 我做错了吗?
    • @ShoaibAhmed 不,这意味着初始字符串根本无法转换,例如从一个字符开始。您可以用 try/catch 块包围 x = std::stof... 行。查看更新的编辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 2016-08-02
    相关资源
    最近更新 更多