[英]Trying to understand cin behavior
我正在编写从stdin获取(巨大)输入流并将其读入浮点向量的软件。 我想捕获这种情况,即流包含逗号之类的字符,或者不接受它,或者只是忽略了无法解析为float的所有内容(以更容易实现的为准,我没有优先选择)。 我注意到以下行为:当我打电话时
echo "1.4, -0.7 890 23e-3" | ./cintest
这个版本
#include <iostream>
using std::endl;
using std::cin;
using std::cout;
int main ( int argc, const char* argv[] ){
float val;
while (cin >> val) {
cout << val << endl;
}
return 0;
}
版画
1.4
而这个版本
#include <iostream>
using std::endl;
using std::cin;
using std::cout;
int main ( int argc, const char* argv[] ){
float val;
while (cin) {
cin >> val;
cout << val << endl;
}
return 0;
}
版画
1.4
0
没有逗号,第一个打印
1.4
-0.7
890
0.023
而第二个打印
1.4
-0.7
890
0.023
0.023
有人可以解释一下这是怎么回事吗?
您的代码的第一个版本
while (cin >> val) {
尝试解析浮点数, 然后检查流状态是否良好。 (特别是,它调用operator>>
进行提取,这将在出错时设置failbit
,然后使用bool转换来测试failbit
)。
所以,如果流状态是坏的(因为它无法转换,
为float),不进入循环体。 因此,它在第一次转换失败时终止。
第二版
while (cin) {
cin >> val;
检查流状态是否良好(这只会告诉您先前的转换已成功),然后尝试解析浮点数,然后假定未检查就成功了。 在使用float值之前,应该在转换后检查流状态,在这种情况下,float值是前一次迭代遗留下来的。
在正确的实现中,当转换失败时,您应该检查一下fail()
是否为true但eof()
是否为false(即,转换是由于文件末尾以外的某种原因而失败)。 在这种情况下,请使用ignore()
放弃输入-您可以要求使用空格(并忽略直到下一个空格),或者仅忽略一个字符并重试。
请注意,上面链接的ignore
文档包括带有正确错误处理的示例代码。 如果我们选择在转换失败时跳过单个字符,则您的代码将变为:
for(;;) {
float val;
std::cin >> val;
if (std::cin.eof() || std::cin.bad()) {
break;
} else if (std::cin.fail()) {
std::cin.clear(); // unset failbit
std::cin.ignore(1); // skip next char
} else {
std::cout << val << '\n';
}
}
您的结果有难同当的做>>
失败。
在两个版本中,您都读取了值并到达了逗号(或EOF)。 读显然失败了,因为,
和EOF都不是有效整数>>
可以解析。 因此>>
的返回值(流本身)将转换为false
,并且您在第一个版本中退出循环(这是它的工作方式)。
但是,在第二个版本中(这通常不是您应该做的),您仍在打印出最终以val
任何值。 在C ++ 11之前的C ++中, val
保持不变。 因为C ++ 11 >>
在失败时写入0
。
TL; DR:您的第二个版本将循环停止到很晚,并写入一遍垃圾。
这是因为在第二个中您有一个错误。
您应该始终检查格式化的输入operator>>
真正起作用。
所以这段代码:
cin >> val;
cout << val << endl;
应写为:
if (cin >> val) {
cout << val << endl;
}
如果operator>>
失败。 然后,它将在流上设置失败位之一,而不将任何值放入val
。 因此,无需打印val
因为没有放入任何内容。
这就是为什么您的第二个版本在没有剩余数据可读取时会打印垃圾的原因。 读取失败,然后打印出一个值。 然后,您尝试重新启动循环(失败)。
第一个正常工作。
while (cin >> val) {
cout << val << endl;
}
因为您读取了一个值,所以在进入循环之前请先检查读取是否有效。
std :: cin是std :: istream的实例
如果在任何时候出现逗号或任何无效的数据类型,操作符>>都会失败。 因此,您的代码将显示最后一个已知的值“ val”。
此处链接是“ std :: istream >>”的参考
http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.