为什么将iostream :: eof放在循环条件(即`while(!stream.eof())`)内?
我刚刚在此答案中找到一条评论,说在循环条件下使用iostream::eof
是“几乎肯定是错误的”。 我通常使用while(cin>>n)
类的东西-我猜它隐式地检查EOF。
为什么显式地使用while (!cin.eof())
检查eof是错误的?
与在C语言中使用scanf("...",...)!=EOF
有什么不同(我经常会毫无问题地使用它)?
#1楼
底线顶部:在正确处理空白的情况下,以下是可以使用eof
方式(甚至在错误检查方面比fail()
更可靠):
while( !(in>>std::ws).eof() ) { int data;in >> data;if ( in.fail() ) /* handle with break or throw */; // now use data
}
( 感谢Tony D提出的突出显示答案的建议。请参见下面的评论,以获取一个示例来说明为什么它更可靠。 )
反对使用eof()
的主要论点似乎缺少有关空格的重要意义。 我的主张是,明确地检查eof()
不仅不“ 总是错误 ”-在该线程和类似的SO线程中似乎是压倒一切的意见-而且通过正确处理空白,它可以提供更清洁的环境。和更可靠的错误处理,并且始终是正确的解决方案(尽管不一定是最麻烦的)。
总结一下建议的“正确”终止和读取顺序如下:
int data;
while(in >> data) { /* ... */ }// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
由于读取尝试超出eof而导致的失败被视为终止条件。 这意味着,除了eof之外,没有简单的方法来区分成功的流和确实失败的流。 采取以下流:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
以所有三个输入的设置failbit
终止。 在第一个和第三个中,还设置了eofbit
。 因此,经过循环之后,需要非常难看的额外逻辑来区分适当的输入(第一)和不正确的输入(第二和第三)。
而采取以下措施:
while( !in.eof() )
{ int data;in >> data;if ( in.fail() ) /* handle with break or throw */; // now use data
}
在这里, in.fail()
验证只要有东西要读,它就是正确的东西。 它的目的不仅仅是一个while循环终止符。
到目前为止,一切都很好,但是如果流中存在尾随空间,将会发生什么?这听起来像是主要反对将eof()
作为终止符的问题?
我们不需要放弃错误处理。 只是吃掉空白:
while( !in.eof() )
{ int data;in >> data >> ws; // eat whitespace with std::wsif ( in.fail() ) /* handle with break or throw */; // now use data
}
在设置eofbit
而不是failbit
同时, std::ws
跳过流中任何潜在的(零个或多个)尾随空间。 因此,只要至少要读取一个数据, in.fail()
按预期工作。 如果全空白流也可接受,那么正确的格式是:
while( !(in>>ws).eof() )
{ int data;in >> data; if ( in.fail() ) /* handle with break or throw */; /* this will never fire if the eof is reached cleanly */// now use data
}
简介:正确构造的while(!eof)
不仅可能而且没有错误,但允许将数据定位在范围内,并提供了更清晰的错误检查与常规业务的分离。 话虽这么说, while(!fail)
无疑是一个更常见,更简洁的习惯用法,并且在简单(每种读取类型的单个数据)场景中可能是首选。
#2楼
其他答案已经解释了为什么while (!stream.eof())
的逻辑错误以及如何解决。 我想专注于一些不同的东西:
为什么显式地使用
iostream::eof
检查iostream::eof
错误的?
一般而言, 仅检查eof
是错误的,因为流提取( >>
)可能会失败而不会到达文件末尾。 如果您有int n; cin >> n;
int n; cin >> n;
并且流包含hello
,则h
不是有效数字,因此提取操作将在不到达输入结尾的情况下失败。
此问题与尝试从流中读取之前检查流状态的一般逻辑错误结合在一起,这意味着对于N个输入项,循环将运行N + 1次,从而导致以下症状:
如果流为空,则循环将运行一次。
>>
将失败(没有要读取的输入),并且所有应设置的变量(通过stream >> x
)实际上都未初始化。 这导致处理垃圾数据,这可能表现为无意义的结果(通常是巨大的数字)。(如果您的标准库符合C ++ 11,则现在情况有所不同:失败
>>
现在将数字变量设置为0
而不是未初始化它们(char
除外)。)如果流不为空,则循环将在最后一个有效输入之后再次运行。 由于所有
>>
运算在上次迭代中均失败,因此变量很可能会保留前一次迭代中的值。 这可以表现为“最后一行被打印两次”或“最后一个输入记录被处理两次”。(这与C ++ 11(见上文)相比应该有所不同:现在,您将获得零的“幻像记录”,而不是重复的最后一行。)
如果流包含格式错误的数据,但仅检查
.eof
,则会导致无限循环。>>
将无法从流中提取任何数据,因此循环旋转到位而不到达终点。
回顾:解决方案是测试>>
操作本身是否成功,而不是使用单独的.eof()
方法: while (stream >> n >> m) { ... }
,就像在C中测试一样scanf
调用本身的成功: while (scanf("%d%d", &n, &m) == 2) { ... }
。
#3楼
因为iostream::eof
仅在读取流的末尾后才返回true
。 这并不表示,下一次读取将是流的末尾。
考虑一下(假设下一个读取将在流的末尾):
while(!inStream.eof()){int data;// yay, not end of stream yet, now read ...inStream >> data;// oh crap, now we read the end and *only* now the eof bit will be set (as well as the fail bit)// do stuff with (now uninitialized) data
}
反对:
int data;
while(inStream >> data){// when we land here, we can be sure that the read was successful.// if it wasn't, the returned stream from operator>> would be converted to false// and the loop wouldn't even be entered// do stuff with correctly initialized data (hopefully)
}
关于第二个问题:
if(scanf("...",...)!=EOF)
是相同的
if(!(inStream >> data).eof())
和不一样
if(!inStream.eof())inFile >> data
#4楼
因为如果程序员不编写while(stream >> n)
,他们可能会这样写:
while(!stream.eof())
{stream >> n;//some work on n;
}
这里的问题是,如果不首先检查流读取是否成功,就无法some work on n
进行some work on n
,因为如果不成功,则some work on n
的some work on n
会产生不希望的结果。
整个问题是, 尝试从流中读取后设置了 eofbit
, badbit
或failbit
。 因此,如果stream >> n
失败,则会立即设置eofbit
, badbit
或failbit
,因此如果您while (stream >> n)
编写while (stream >> n)
更加习惯,因为如果从中读取数据失败,则返回的对象stream
将转换为false
。流,因此循环停止。 如果读取成功并且循环继续,它将转换为true
。
为什么将iostream :: eof放在循环条件(即`while(!stream.eof())`)内?相关推荐
- python无限循环条件循环_Python - 条件控制、循环语句 - 第十二天
Python 条件控制.循环语句 end 关键字 关键字end可以用于将结果输出到同一行,或者在输出的末尾添加不同的字符,实例如下: Python 条件语句是通过一条或多条语句的执行结果(True 或 ...
- 具有循环条件gan的实值(医疗)时间序列生成-2017
REAL-VALUED (MEDICAL) TIME SERIES GENERATION WITH RECURRENT CONDITIONAL GANS ABSTRACT 生成对抗网络(GANs)作为 ...
- linux+while循环多条件,有效的while循环条件客户端选择(TCP连接在Linux - C)
我想做一个TCP文件传输连接,使客户端可以选择他想做什么"任务"(列出目录中的文件,上传,下载一个文件),但是一旦他做出选择就不会终止.这意味着他可以在每个环节做更多的选择.有效的 ...
- html 列表循环_python web开发:内置标签与过滤器/循环/条件判断
专注于python领域优质技术,欢迎关注 这一篇教程,我们继续了解Django中模板的使用. 主要内容如下: 内置标签和过滤器: 模板中使用循环: 模板中添加条件判断. 一.内置标签和过滤器 Djan ...
- 啪啪打脸!领导说:try-catch要放在循环体外!
这是我的第 206 期分享 作者 | 王磊 来源 | Java中文社群(ID:javacn666) 转载请联系授权(微信ID:GG_Stone) 哈喽,亲爱的小伙伴们,技术学磊哥,进步没得说!欢迎来到 ...
- java for循环 条件_Java for循环(十三)
for循环 for语句是应用最广泛.功能最强的一种循环语句.大部分情况下,for循环可以代替while循环.do while循环,这3种循环可以相互替换~ for语句是一种在程序执行前就要先判断条件表 ...
- (理解)单链表算法循环条件while(p)和while(p->next)有什么区别
[问题]: 单链表的删除算法中循环条件(p->next&&j<i)和插入算法中的循环条件(p&&(j<i))有什么区别? //在带头节点的单链表L中, ...
- EOF的用法(while(scanf(“%d“,n) != EOF))和~取反的用法(while(~scanf(“%d“,n)))
文章目录 多组输入输出 输入固定数据量 EOF的用法 ~取反的用法 另一种写法,只针对特定标识符结束 扩展 多组输入输出 我们在做题中会有出现以下的情况, 情况一:题中要求在输入数据第一行给出固定数据 ...
- 控件必须放在具有 runat=server 的窗体标记内 错误解决解决方法
今天在开发的时候遇到了一个问题,情况大致是这样的:我的页面需要一个导出到Excel的功能,于是我便利用GridView控件的RenderControl()来输出数据,可是在运行的时候却遇到了" ...
最新文章
- Redis 笔记(08)— 事务(一次执行多条命令、命令 watch/multi/exec/discard、错误处理)
- 与后台交互方法一 ——Ajax
- python安装pymssql
- 计算机组装学位,《计算机组装与维护》虚拟实验界面设计与制作学位论文 .doc...
- python subprocess-更优雅的创建子进程
- JS-立即执行函数(function(){...})() amp;amp; (function(){...})()
- 如何使用Java 8流快速替换列表中的元素
- 避免下载Word/Excel文件时被IE开启
- chrome vue.js插件文档_常用web研发技术文档,这里都给你准备好了
- Linux 10分钟掌握Linux常用开发工具及编译的四个过程
- 使用vSphere Power Cli初始化数据中心
- 如何使用jMeter对某个OData服务进行高并发性能测试
- python调用perl_从Python调用Perl脚本不断返回值
- matlab自带优化工具箱,二元一次函数
- MODIS数据快速下载方法
- 【科来】网络异常行为分析学习笔记
- Microsoft Excel 教程:如何在 Excel 中创建自定义数字格式?
- 如何解决No EPCS layout data --- looking for section [EPCS-XXXXXX]
- 什么是数据库存储过程?
- 2019/07/03 分布式系统概述(01)