无效数字总是降到0?

时间:2014-01-20 00:52:46

标签: c++ cin

cout << "Enter a positive integer or zero: ";
getline(cin, streamStr);
stringstream(streamStr) >> number;
if (!number) {
    cout << "invalid input detected or the input is too big.\n";
    return 1;
}

像“%234”或“sdf2334”这样的输入总是会降为0,这在bool表达式中为false,但0仍然是一个数字。 如何检查输入是否真的无效,如“%234”??

4 个答案:

答案 0 :(得分:5)

您需要检查operator>>的返回值,该值与您正在读取的变量的值不同:

if (stringstream(streamStr) >> number) {
    ...

那么返回的值是什么呢?如果你检查文档,你会发现它本身就是一个流。它转到它的operator bool(因为它在if语句中使用),它反过来返回流的有效性,或者IOW,如果最后一个操作成功。

如果您想确保流不包含任何数字,请使用

if (sstream.rdbuf()->in_avail() > 0) { 
    // something is still there

如果你想允许的话,最后跳过空格:

sstream >> std::ws;

所以,总而言之......

template<typename T, 
    // those are optional
    enable_if<is_default_constructible<T>::value>::type,
    enable_if<is_input_streamable<T>::value>::type
>
optional<T> myRead(string input, bool allowTrailingWs = true) {
    stringstream str(input);
    T val;

    // check parsing
    if (!(str >> val))
        return none;

    // allow whitespace at the end
    if (allowTrailingWs)
        str >> std::ws;

    // check if there's any garbage left
    if (str.rdbuf()->in_avail() > 0)
        return none;

    return val;
}

上面的代码仅用于说明目的。如果你需要更高级的解析,请查看Boost.Spirit。


此外,apparently this isn't guaranteed to work every time。使用:

    auto inputEnd = ss.tellg();
    ss.seekg(0, std::ios::end);
    if (inputEnd == ss.tellg()) {

检查ss是否为空可以帮助解决问题。

答案 1 :(得分:4)

我认为您不了解流的工作原理。请允许我解决你的误解:

如果要评估的数据与该类型的格式要求不对应,则流不会尝试将任何值提取到number。提取工作通过流逐个迭代字符序列中的每个字符,并测试每个字符作为提取所针对的类型的可行数据。如果角色不可行,则提取停止(这就是您在输入"2342fdsf"之类的内容时看到成功的原因;流将一直提取,直到找到无效字符。"2342"是整数的有效字符虽然"f"不是)

如果流找到无效字符,则不对该变量做任何进一步处理(在本例中为number)。实际上,它是实现定义的,如果提取无法生成任何字符,则未初始化变量具有什么值。考虑到这一点,检查操作数的值以确定I / O是否失败是有潜在危险的。这是检查流状态的地方:

std::istringstream iss(streamStr);

if (iss >> number)
{
    std::cout << "Extraction produced: " << number << '\n';
}

如果提取失败,则流将设置适当的位。然后,流将使用operator bool()(或operator void*() pre-C ++ 11隐式转换为布尔值,随后将转换为布尔值)。布尔函数将使用!this->fail()检查流状态(检查badbitfailbit),如果函数返回true,则执行if正文。

如果流处于良好状态(!this->fail()返回false),则表示提取未能生成值,if语句体未被评估。

答案 2 :(得分:1)

通过在条件检查中包含提取,而不是您尝试提取的内容的值。

答案 3 :(得分:0)

假设number必须是char值,请尝试使用有助于处理字符串的cctype库。它具有诸如

之类的功能
isdigit(Char_Exp) //Returns true if the value is a digit

isctrl(Char_Exp) //Returns true if the value is a control character like %(modulus) 

以下是C ++ cctype库引用的链接:cctype library reference

要测试number我建议你创建一个Boolean类型的函数,以便它一次测试所有可能的输入错误。