C 程序将最后一行打印两次(文件 I/O)

vvv*_*vsg 5 c

最近我正在阅读 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)

Sig*_*ndo 4

要点是 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 的建议重复同一行两次。