到目前为止提出的每个解决方案都很好地解释了 OP 代码错误的原因。但大多数人对问题的解决方案都不正确。
如前所述,在您尝试读取文件末尾之前,不会设置 EOF 标志。最后一次成功的读取可能会读取到(包括)最后一个字符。所以在你的情况下,最后一次读取将从文件中读取 5 然后打印它。然后我们租用者进入循环(这将起作用,因为最后一次读取没有读取超过文件末尾,因此 EOF 为假)。您读取下一个字符的尝试将失败,f >> x
并且变量“x”将保持不变(在您的代码中,这意味着它的最后一个值读取为 5)然后被打印。
解决方案是在完成读取后测试流的状况以确保其正常工作。注意:您不应该专门测试 EOF 还有其他不良状态。如果进入其他不良状态之一,当前代码将进入无限循环。要检查对象上的所有坏位,请调用 fail()。所以最简单的解决方案是将读取放入while测试(见下文)
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
int x;
ifstream f;
f.open("note");
while(f>>x)
{
cout<<x<<endl;
}
return 0;
}
这是因为 >> 运算符返回一个流。当流对象在布尔上下文中使用时,它会转换为可以表示真/假的类型(出于技术原因,这不是布尔值,但您可以将其视为布尔值)。返回的值取决于流的状态。如果流处于良好状态,那么它将(在布尔上下文中)评估为真,从而允许进入循环,如果流对象处于无效状态(即 EOF(或其他失败状态)为真),则它将评估为 false 并且不进入循环。
注意:转换实际上是在流上调用 fail() 来测试状态。
如果您的代码很复杂,并且您无法将状态作为读取的一部分进行测试。然后在每次读取之后,您必须测试对象的状态以验证它是否有效。
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
int x;
ifstream f;
f.open("note");
while(f)
{
f>>x;
if (f) // dont' use f.eof() there are other bad states.
{ // This will actuall call f.fail() which test for all bad states.
// Thus it only prints if the read worked.
cout<<x<<endl;
}
// Alternatively you can put the read into the if
if ( f >> x)
{
// STUFF
}
}
return 0;
}
回应吉姆的评论。
一旦使用 >> 运算符从流中读取了一个数字。不读取其他字符。要证明这是真的,请尝试以下代码:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream file("txt");
std::string line;
int x;
while(f >> x)
{
std::getline(f, line); // If the '\n' was read then
// this code would remove the next line.
// As it works correctly it simply removes then
// characters upto the newline character after the number.
std::cout << x << "\n";
}
}