【问题标题】:fgetc Always returns EOFfgetc 总是返回 EOF
【发布时间】:2014-09-18 17:28:07
【问题描述】:

在尝试计算文本文件中的行数时,我注意到 fgetc 总是返回 EOF。此代码在 Freebsd 10 上运行,但现在它不适用于 Mac OSX。我检查了文件看它是否为空,它不是,它的大小约为 1 KB,包含 16 行。我添加了一行来寻找文件的开头,认为这是问题所在,但它仍然返回 EOF。那么为什么 fgetc 总是返回 EOF?

 int getLines(int listFd, int *lines)
 {

     /* Declarations */
     *lines = 0;
     int ch;
     FILE *list;

     /* Get File Stream */
     list = fdopen(listFd, "r");
     if(list == NULL)
     {
         printf("Can't Open File stream\n");
         return -1;
     }

     /* Seek To beginning Of file */
     fseek(list, 0, SEEK_SET);

     /* Get Number of Lines */
     while(!feof(list))
     {
         ch = fgetc(list);
         if(ch == '\n')
         {
             lines++;
         }

         else if(ch == EOF)
         {
             break;
         }
     }

     printf("lines: %d\n", *lines);

     /* Clean up and Exit */
     fclose(list);

    return 0;
}

【问题讨论】:

  • feof 循环有什么用?
  • 由于line++;,您可能遇到了未定义的行为。那应该是++(*line);
  • 不要使用feof 来确定何时终止循环。使用fgetc 返回的值。 (您可以在循环终止后调用feof 和/或ferror 来了解为什么它会终止。)常见的成语是while ((ch = fgetc(list)) != EOF) { /* ... */ }
  • 您传入一个文件描述符并使用fdopen 打开一个引用它的FILE*。为什么不首先使用FILE*?该文件描述符来自哪里,它指的是什么?您说“文件”存在并且大小约为 1KB -- 什么文件?

标签: c macos freebsd fgetc


【解决方案1】:

fgetc() 应该最终返回EOF。代码的另一个问题肯定是混淆了行为和诊断。很好的测试IO函数的结果。

int getLines(int listFd, int *lines) {
  ...
  *lines = 0;
  ...
  if (fseek(list, 0, SEEK_SET)) puts("Seek error");
  ...
    ch = fgetc(list);
    if (ch == '\n') {
      // lines++;
      (*lines)++;  // @R Sahu 
    }
   ...
   printf("lines: %d\n", *lines);

   if (ferror(list)) puts("File Error - unexpected");
   if (feof(list)) puts("File EOF - expected");
}

其他东西:

以下代码是文件结束条件的冗余测试

/* Get Number of Lines */
while(!feof(list)) {
  ch = fgetc(list);
  ...
  else if(ch == EOF) {
    break;
  }
}

建议的简化 (@Keith Thompson)

 /* Get Number of Lines */
 while( (ch = fgetc(list)) != EOF) {
   if(ch == '\n') {
     (*lines)++;
   }
 }

关于文件行数的小问题:如果文件在最后的'\n' 之后有文本,那会算作一行吗?建议:

*lines = 0;
int prev = '\n'; 
/* Get Number of Lines */
while( (ch = fgetc(list)) != EOF) {
  if(prev == '\n') {
    (*lines)++;
  }
  prev = ch;
}

【讨论】:

  • 我已经切换到你的底部建议,除了循环下方的 ferror 并且 ferror 不断设置并且 perror 返回设备未配置。
  • 1) 显示listFd 的设置方式。 2)不妨放弃fseek()
  • 在调用此函数之前,文件可能存在与其相关联的错误。使用clearerr()rewind() 而不是fseek(stream, 0L, SEEK_SET),因为这也会在执行任何fgetc() 之前清除流的指示器和/或测试错误。
猜你喜欢
  • 2013-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
  • 2013-08-16
相关资源
最近更新 更多