Xeo*_*Xeo 518
因为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
}
Run Code Online (Sandbox Code Playgroud)
反对这个:
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)
}
Run Code Online (Sandbox Code Playgroud)
关于你的第二个问题:因为
if(scanf("...",...)!=EOF)
Run Code Online (Sandbox Code Playgroud)
是相同的
if(!(inStream >> data).eof())
Run Code Online (Sandbox Code Playgroud)
和不一样的
if(!inStream.eof())
inFile >> data
Run Code Online (Sandbox Code Playgroud)
sly*_*sly 98
底线: 正确处理空白区域,以下是如何eof使用(甚至比fail()错误检查更可靠):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
Run Code Online (Sandbox Code Playgroud)
(感谢Tony D提出强调答案的建议.请参阅下面的评论,了解为什么这样做更为强大.)
反对使用的主要论点eof()似乎缺少关于白色空间作用的重要微妙之处.我的主张是,eof()明确地检查不仅不是" 总是错误的 " - 这似乎是在这个和类似的SO线程中的最重要的意见 - 但是通过适当处理白色空间,它提供了更清洁和更可靠的错误处理,并且始终是正确的解决方案(虽然,不一定是最简洁的).
总结一下建议的"正确"终止和阅读顺序如下:
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
由于超过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
}
Run Code Online (Sandbox Code Playgroud)
在这里,in.fail()验证只要有东西要读,它就是正确的.它的目的不仅仅是一个while循环终止符.
到目前为止一切都那么好,但是如果流中有尾随空间会发生什么 - 听起来像是eof()作为终结者的主要问题?
我们不需要放弃我们的错误处理; 只是吃掉了白色空间:
while( !in.eof() )
{
int data;
in >> data >> ws; // eat whitespace with std::ws
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
Run Code Online (Sandbox Code Playgroud)
std::ws在设置时eofbit,不会failbit跳过流中任何潜在的(零个或多个)尾随空格.因此,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
}
Run Code Online (Sandbox Code Playgroud)
简介:正确构造while(!eof)不仅可能而且没有错误,但允许数据在范围内进行本地化,并且可以像往常一样更清晰地将错误检查与业务分开.话虽如此,while(!fail)无疑是一种更常见和简洁的习惯用语,并且在简单(每种读取类型的单一数据)场景中可能是首选.
Naw*_*waz 71
因为如果程序员不写while(stream >> n),他们可能写这个:
while(!stream.eof())
{
stream >> n;
//some work on n;
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是,你不能不some work on n先检查流读取是否成功,因为如果它不成功,你some work on n会产生不希望的结果.
整点是,eofbit,badbit,或failbit设置试图从流中读取后.因此,如果stream >> n失败,那么eofbit,badbit或者failbit立即设置,所以如果你写的话它更加惯用while (stream >> n),因为如果从流中读取有一些失败并且因此循环停止,则返回的对象stream转换为false.true如果读取成功并且循环继续,它将转换为.
其他答案已经解释了为什么逻辑错误while (!stream.eof())以及如何解决它。我想专注于一些不同的东西:
为什么显式地使用
iostream::eof错误检查eof ?
一般而言,eof 仅检查是错误的,因为流提取(>>)可能会失败而不会到达文件末尾。如果您有eg int n; cin >> n;并且流包含hello,那么h它不是有效的数字,因此提取将失败而未到达输入的结尾。
此问题与尝试从流中读取之前检查流状态的一般逻辑错误结合在一起,这意味着对于N个输入项,循环将运行N + 1次,从而导致以下症状:
如果流为空,则循环将运行一次。>>将失败(没有要读取的输入),并且所有本应设置为(由stream >> x)的变量实际上都未初始化。这导致处理垃圾数据,这可能表现为无意义的结果(通常是巨大的数字)。
(如果您的标准库符合C ++ 11,则现在情况有所不同:失败>>现在将数字变量设置为,0而不是不初始化它们(chars 除外)。)
如果流不为空,则循环将在最后一个有效输入之后再次运行。由于在最后一次迭代中所有>>操作都会失败,因此变量可能会保留前一次迭代的值。这可以表现为“最后一行被打印两次”或“最后一个输入记录被处理两次”。
(与C ++ 11相比,这应该有所不同(请参见上文):现在您将获得零的“幻像记录”,而不是重复的最后一行。)
如果流包含格式错误的数据,但仅检查.eof,则会导致无限循环。>>将无法从流中提取任何数据,因此循环旋转到位而不到达终点。
回顾一下:解决方案是测试>>操作本身的成功,而不是使用单独的.eof()方法:while (stream >> n >> m) { ... },就像在C中测试scanf调用本身的成功:一样while (scanf("%d%d", &n, &m) == 2) { ... }。
要记住的重要一点是,直到尝试读取失败后inFile.eof(), \xe2\x80\x99 才会变为,因为\xe2\x80\x99 已到达文件末尾。因此,在此示例中,您\xe2\x80\x99 将收到错误。True
while (!inFile.eof()){\n inFile >> x;\n process(x);\n}\nRun Code Online (Sandbox Code Playgroud)\n使这个循环正确的方法是将读取和检查结合到一个操作中,就像这样
\nwhile (inFile >> x)\xc2\xa0\n process(x);\xc2\xa0\nRun Code Online (Sandbox Code Playgroud)\n按照约定,返回我们从中读取的流,并且当流失败(例如到达文件末尾)时,operator>>返回对流的布尔测试。False
所以这给了我们正确的顺序:
\n如果您碰巧遇到其他一些问题,导致您无法正确读取文件,您将无法达到eof()这样的目的。例如,让\xe2\x80\x99s 看看这样的东西
int x;\xc2\xa0\nwhile (!inFile.eof()) {\xc2\xa0\n inFile >> x;\xc2\xa0\n process(x);\n}\xc2\xa0\nRun Code Online (Sandbox Code Playgroud)\n让我们通过一个例子来追溯上面代码的工作原理
\n'1', '2', '3', 'a', 'b'.a.a为 int 时,\xe2\x80\x99 将失败。clear对该流进行读取,否则所有读取该流的尝试都将失败。False,因为我们\xe2\x80\x99 不在文件末尾,因为\xe2\x80\x99 仍在a等待读取。但是,如果我们使用这样的循环,我们将得到所需的输出。
\nwhile (inFile >> x)\n process(x);\nRun Code Online (Sandbox Code Playgroud)\n在这种情况下,流False不仅会在文件结尾的情况下转换,而且在转换失败的情况下也会转换,例如a我们可以将 \xe2\x80\x99t 作为整数读取。
| 归档时间: |
|
| 查看次数: |
56764 次 |
| 最近记录: |