最近我正在阅读 Deitel 的《C How to Program》第 7 版的文件处理部分。为了写入文件,它使用以下示例:
// Fig. 11.2: fig11_02.c
// Creating a sequential file
#include <stdio.h>
int main( void )
{
unsigned int account; // account number
char name[ 30 ]; // account name
double balance; // account balance
FILE *cfPtr; // cfPtr = clients.dat file pointer
// fopen opens file. Exit program if unable to create file
if ( ( cfPtr = fopen( "clients.dat", "w" ) ) == NULL ) {
puts( "File could not be opened" );
} // end if
else {
puts( "Enter the account, name, and balance." );
puts( "Enter EOF to end input." );
printf( "%s", "? " );
scanf( "%d%29s%lf", &account, name, &balance );
// write account, name and balance into file with fprintf
while ( !feof( stdin ) ) {
fprintf( cfPtr, "%d %s %.2f\n", account, name, balance );
printf( "%s", "? " );
scanf( "%d%29s%lf", &account, name, &balance );
} // end while
fclose( cfPtr ); // fclose closes file
} // end else
} // end main
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它首先在 else 块中扫描并打印数据,然后在 while 循环中扫描和打印数据。因为我认为重复两次是没有意义的,所以它只是删除了 if-else 部分并编译了它。好吧,它工作得很好,但后来我意识到它复制了输出文件中的最后一行输入。在 Deitel 版本中则不然。
我的版本有什么问题吗??为什么它会重复最后一行?我认为这可能是循环条件的问题,但我不确定..
编辑:此代码由 Dietel 使用,我不认为这是错误的,因为他正在使用 if-else 来解决 !feof 引起的问题。但我想知道如何在没有 if-else 的情况下修复它。
在没有 if-else 且仅使用循环的编辑版本中,输入和输出为:
输入:
1 test 25.6
2 some 95
Run Code Online (Sandbox Code Playgroud)
输出:
1 test 25.6
2 some 95
2 some 95
Run Code Online (Sandbox Code Playgroud)
要点是 EOF 测试必须始终在 scanf() 之后,并且在打印读取信息之前。
if-else 条件仅用于处理最终的打开错误条件,因此您如何修改代码并不完全清楚。然而人们经常尝试这样做:
while ( !feof( stdin ) ) {
scanf( "%d%29s%lf", &account, name, &balance );
fprintf( cfPtr, "%d %s %.2f\n", account, name, balance );
printf( "%s", "? " );
}
Run Code Online (Sandbox Code Playgroud)
这是错误的,因为当读取最后一个数据时,它不会“读取EOF”(EOF是读完数据后scanf()遇到的条件):只有后续的数据才会执行,并且输出函数将打印错误的数据(前一个数据)那些,由于输入错误而未被覆盖,这就是重复最后一行的原因)。
例如,这是正确的:
for ( ;; ) {
scanf( "%d%29s%lf", &account, name, &balance );
if (feof( stdin )) break;
fprintf( cfPtr, "%d %s %.2f\n", account, name, balance );
printf( "%s", "? " );
}
Run Code Online (Sandbox Code Playgroud)
事实上,我更喜欢它,而scanf()不是按照 Deitel 的建议重复同一行两次。