提问人:Jake 提问时间:2/5/2017 最后编辑:BLUEPIXYJake 更新时间:2/5/2017 访问量:7197
为什么输入文件的最后一行运行了两次?
Why is the last line of my input file running twice?
问:
输入文件
Miller Andrew 65789.87 5
Green Sheila 75892.56 9
Sethi Amit 74900.50 6.1
ifstream inFile;
ofstream outFile;
string laastName;
string firstName;
double salary;
double percent;
double new Salary;
double increase;
inFile.open("Ch3_Ex6Data.txt");
outFile.open("Ch3_Ex6Output.dat");
while(!inFile.eof()) {
inFile >> lastName;
inFile >> firstName;
inFile >> salary;
inFile >> percent;
percent /= 100;
increase = salary * percent;
newSalary = increase + salary;
outFile << firstName << " " << lastName << " ";
outFile << setprecision(2) << fixed << newSalary << endl;
}
inFile.close();
outFile.close();
return 0
}
输出文件
Andrew Miller 69079.36
Sheila Green 82722.89
Amit Sethi 79469.43
Amit Sethi 74946.19
我的问题是为什么最后一行被输出两次,为什么它与第一行不同?我不明白为什么循环会继续下去。文件标记的末尾没有命中吗?我能够通过输入索引变量并通过说 && 小于 index 将第二个条件放入 while 循环来对其进行硬编码,但我觉得我不应该这样做。
答:
您不检查是否有任何读取成功。无论读取是否失败,您都可以输出内容。
您的代码似乎期望预测将来的读取是否会成功。但它并不能预测未来。将来的读取仍可能失败。eof()
最后一次循环时,所有读取操作都失败,因此所有变量仍具有其原始值。然后再次输出最后一行。然后你终于检查了错误(对循环中时间的调用),但为时已晚。eof()
相反,为什么不直接检查您的读取是否成功呢?这才是你真正想知道的。
顺便说一句,这是一个非常常见的错误,出现在许多不同的上下文中。錯誤的症鍵是你試圖檢查某件事成功所需的所有條件,然後假設這件事會成功,因為你檢查了它可能失敗的每一種方式。这是一个坏主意,至少有三个原因。首先,这通常是浪费精力。其次,在检查和尝试操作之间,情况可能会发生变化。第三,你可能错过了它可能失败的方式之一。
在这里,这三个原因都适用。
评论
当输入操作到达流的末尾时(如:读取最后一行),但当输入操作尝试在流结束后读取数据时(如:在没有更多数据时尝试读取数据,因为已到达文件流的末尾),则不会设置 eofbit。
这意味着读取文件中最后一行的完成不会设置文件位的末尾,并且仍然是 false。因此,您的程序会进入下一个循环迭代,并且仅在行中的下一次读取之后运行eof()
inFile >> lastName;
执行,设置 EOFBIT。 最后一行打印两次,因为上一次循环迭代期间的所有读取操作都失败,并且变量仍具有上一次循环迭代的值。
编辑:为了防止这种情况,您可以检查读取操作是否成功,例如在循环中使用 inFile.good():
while(!inFile.eof()) {
inFile >> lastName;
inFile >> firstName;
inFile >> salary;
inFile >> percent;
//check whether no errors occurred during the input operations
if (!inFile.good())
{
//input failure, leave the loop
break;
}
percent /= 100;
increase = salary * percent;
newSalary = increase + salary;
outFile << firstName << " " << lastName << " ";
outFile << setprecision(2) << fixed << newSalary << endl;
}
问题是它没有做你认为它做的事情。eof
想象一下,你走在地板上,一块接一块地,捡起地板上的东西,把它放在你的口袋里,然后显示(打印)你的口袋里的东西。
当你把脚放在最后一块瓷砖上时,地板还没有“结束”,你的鼻子仍然是安全的。你(还没有)砸墙。你填满口袋并打印它们。
eof
然后,告诉你什么时候你的鼻子被打破了,而不是什么时候瓷砖是最后一个。
所以,你在最后一块瓷砖上,检查你的鼻子,发现它没问题,然后向前迈出一步。你的鼻子现在在流血,没有什么可以偷看的放在我们的口袋里,你的口袋里还装着......他们以前拥有的东西。
你打印你口袋里的东西(再次),然后检查你的鼻子。它坏了:你退出了。
解决这个问题的惯用方法是这样的:
while(inFile >> lastName
>> firstName
>> salary
>> percent)
{
//all your computation here
}
我想你应该自己明白为什么。
你用过,但你声明了,所以删除并小心。
lastName
laastName
a
double new Salary
:这是怎麽?- 我想你的意思是:如果是这样,请阅读一本关于在 C++ 中命名变量的有用书,因为你故意搞砸了。double NewSalary
while(!inFile.eof())
不建议放弃使用。末尾缺少分号。
;
main
您的代码将如下所示:
int main() { ifstream inFile; ofstream outFile; string lastName; string firstName; double salary; double percent; double newSalary; double increase; inFile.open("Ch3_Ex6Data.txt"); outFile.open("Ch3_Ex6Output.dat"); while(inFile >> lastName >> firstName >> salary >> percent){ percent /= 100; increase = salary * percent; newSalary = increase + salary; outFile << firstName << " " << lastName << " "; outFile << setprecision(2) << fixed << newSalary << endl; } inFile.close(); outFile.close(); return 0; }
评论
while(!inFile.eof()) {
while( inFile >> lastName >> firstName >> salary >> percent)
{}