为什么我的输入文件的最后一行 运行 两次?
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
我的问题是为什么最后一行输出两次,为什么它与第一行不同?我不明白为什么循环继续。文件结尾标记没有命中吗?我能够通过放入一个索引变量并通过说 && 小于索引将第二个条件放入 while 循环来对其进行硬编码,但我觉得我无论如何都不应该这样做。
您不检查是否有任何读取成功。无论读取是否失败,您都会输出内容。
您的代码似乎期望 eof()
预测未来的读取是否会成功。但它并不能预测未来。未来的读取仍然会失败。
你最后一次循环,所有的读取操作都失败了,所以所有的变量仍然是它们的原始值。然后再次输出最后一行。然后你终于检查错误(调用 eof()
循环中的时间),但为时已晚。
相反,为什么不检查您的读取是否成功?这才是你真正想知道的。
顺便说一句,这是一个非常常见的错误,出现在许多不同的上下文中。错误的症结在于你试图检查某件事成功的所有必要条件,然后假设这件事会成功,因为你检查了它可能失败的所有方式。出于至少三个原因,这是一个坏主意。首先,这通常是浪费精力。其次,在您检查和尝试操作之间,情况可能会发生变化。第三,您可能错过了它可能失败的一种方式。
在这里,所有三个原因都适用。
当输入操作到达流的末尾时(如:读取最后一行),eofbit 不会被设置,但当输入操作试图在流结束后读取数据时(如:尝试在没有更多数据剩余时读取数据,因为已到达文件流的末尾)。
这意味着完成读取文件中的最后一行 不会 设置文件结束位,并且 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
没有按照您的想法去做。
想象一下,您正走在地板上,一块接一块地,捡起地板上的东西,将其放入您的口袋并显示(打印)您口袋里的物品。
当你把脚放在最后一块瓷砖上时,地板还没有 "ended",你的鼻子仍然安全。你还没有(还)砸墙。你 fill-up 口袋并打印出来。
eof
,然后,告诉你你的鼻子是什么时候坏掉的,而不是什么时候瓷砖是最后一个。
所以,你在最后一块砖上,检查你的鼻子,发现没问题,再往前走一步。你的鼻子现在在流血,没有什么东西可以偷看放在我们的口袋里,你的口袋里还有……他们以前的东西。
您(再次)打印口袋里的东西,然后检查鼻子。坏了:你退出。
解决该问题的惯用方法是:
while(inFile >> lastName
>> firstName
>> salary
>> percent)
{
//all your computation here
}
我想你应该自己明白为什么。
你使用了 lastName
但你声明了 laastName
所以删除 a
并小心。
double new Salary
:这是什么? - 我想你的意思是:double NewSalary
如果是这样,请阅读一本关于在 C++ 中命名变量的有用书籍,因为你故意搞砸了。
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;
}
输入文件
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
我的问题是为什么最后一行输出两次,为什么它与第一行不同?我不明白为什么循环继续。文件结尾标记没有命中吗?我能够通过放入一个索引变量并通过说 && 小于索引将第二个条件放入 while 循环来对其进行硬编码,但我觉得我无论如何都不应该这样做。
您不检查是否有任何读取成功。无论读取是否失败,您都会输出内容。
您的代码似乎期望 eof()
预测未来的读取是否会成功。但它并不能预测未来。未来的读取仍然会失败。
你最后一次循环,所有的读取操作都失败了,所以所有的变量仍然是它们的原始值。然后再次输出最后一行。然后你终于检查错误(调用 eof()
循环中的时间),但为时已晚。
相反,为什么不检查您的读取是否成功?这才是你真正想知道的。
顺便说一句,这是一个非常常见的错误,出现在许多不同的上下文中。错误的症结在于你试图检查某件事成功的所有必要条件,然后假设这件事会成功,因为你检查了它可能失败的所有方式。出于至少三个原因,这是一个坏主意。首先,这通常是浪费精力。其次,在您检查和尝试操作之间,情况可能会发生变化。第三,您可能错过了它可能失败的一种方式。
在这里,所有三个原因都适用。
当输入操作到达流的末尾时(如:读取最后一行),eofbit 不会被设置,但当输入操作试图在流结束后读取数据时(如:尝试在没有更多数据剩余时读取数据,因为已到达文件流的末尾)。
这意味着完成读取文件中的最后一行 不会 设置文件结束位,并且 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
没有按照您的想法去做。
想象一下,您正走在地板上,一块接一块地,捡起地板上的东西,将其放入您的口袋并显示(打印)您口袋里的物品。
当你把脚放在最后一块瓷砖上时,地板还没有 "ended",你的鼻子仍然安全。你还没有(还)砸墙。你 fill-up 口袋并打印出来。
eof
,然后,告诉你你的鼻子是什么时候坏掉的,而不是什么时候瓷砖是最后一个。
所以,你在最后一块砖上,检查你的鼻子,发现没问题,再往前走一步。你的鼻子现在在流血,没有什么东西可以偷看放在我们的口袋里,你的口袋里还有……他们以前的东西。
您(再次)打印口袋里的东西,然后检查鼻子。坏了:你退出。
解决该问题的惯用方法是:
while(inFile >> lastName
>> firstName
>> salary
>> percent)
{
//all your computation here
}
我想你应该自己明白为什么。
你使用了
lastName
但你声明了laastName
所以删除a
并小心。double new Salary
:这是什么? - 我想你的意思是:double NewSalary
如果是这样,请阅读一本关于在 C++ 中命名变量的有用书籍,因为你故意搞砸了。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; }