我编写了以下代码来输入文件中的数字,但是最后一个数字被打印了两次,这让我感到困惑。什么是可能的答案。 提前谢谢。
代码:
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
int x;
ifstream f;
f.open("note");
while(!f.eof()){
f>>x;
cout<<x<<endl;
}
return 0;
}
给出输出:
1
2
3
4
5
5
文件说明的内容是:
1
2
3
4
5
答案 0 :(得分:5)
这是因为EOF
标志仅在您尝试阅读EOF
时设置。 (这是一个错误标志)
所以你最好在循环结束时测试f.eof()
。
答案 1 :(得分:5)
让我尝试比以前的答案更有启发性。 f>>x
读取一个整数,以便扫描输入数字。它看到'5'然后'\ n',这不是一个数字,所以它在'5'之后停止并将x设置为5.它还没有遇到eof,你的循环再次执行,然后是f>>x
读取'\ n'然后当它击中eof时失败,保持x
不变,然后再次打印5。因此,您需要在阅读后和打印前进行测试。最简单(也是首选)的方法是
while(f>>x)
cout<<x<<endl;
你应该不做类似
的事情do{
f>>x;
cout<<x<<endl;
}while(!f.eof());
(在阅读之后和打印之前没有测试)因为如果输入文件不包含任何数字会导致未定义的行为 - x
被酉化并且你将打印垃圾(或者可能会炸毁世界,但可能不是。)
答案 2 :(得分:3)
到目前为止提出的每个解决方案都很好地解释了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;
}
这是因为&gt;&gt;运算符返回流。当在布尔上下文中使用流对象时,它将被转换为可以表示true / false的类型(出于技术原因,这不是bool,但您可以将其视为bool)。返回的值取决于流的状态。如果流处于良好状态,那么它将(在布尔上下文中)评估为true,从而允许输入循环,如果流对象处于无效状态(即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;
}
回应吉姆的评论 使用&gt;&gt;从流中读取数字后运营商。没有其他字符被读取。要显示这是真的,请尝试以下代码:
#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";
}
}