无效数字总是降到0

invalid numbers always fall to 0?

本文关键字:数字 无效      更新时间:2023-10-16
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表达式中是错误的,但0仍然是一个数字。如何检查输入是否真的像"%234"一样无效??

您需要检查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;
}

上面的代码是,仅用于说明。如果您需要更高级的解析,请查看BoostSpirit.


此外,显然这并不能保证每次都有效。使用:

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

检查ss是否为空可能有助于解决此问题。

我认为您不了解流是如何工作的。请允许我解决您的误解:

如果正在评估的数据不符合类型的格式化要求,则流不会尝试将任何值提取到number中。提取的工作方式是流逐个迭代字符序列中的每个字符,并将每个字符作为提取目标类型的可行数据进行测试。如果字符不可行,提取将停止(这就是为什么您在输入类似"2342fdsf"的字符时看到成功的原因;流将继续提取,直到找到无效字符。"2342"是整数的有效字符,而"f"不是)

如果流发现一个无效字符,则不对变量(在本例中为number)执行任何进一步操作。事实上,它是由实现定义的,如果提取无法生成任何字符,那么未初始化的变量的值是多少。考虑到这一点,检查操作数的值以确定I/O是否失败是潜在的危险。这就是检查流状态的作用:

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

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

如果流不是处于良好状态(!this->fail()返回false),则意味着提取无法生成值,并且if语句体将不求值。

通过在条件检查中封装提取,而不是试图提取到的东西的值。

假设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库参考

为了测试number,我建议您创建一个布尔类型的函数,以便它一次测试所有可能的输入错误。