如何计算文件中的换行符,但不计算只是换行符的行?

时间:2017-04-25 23:35:38

标签: c file newline c99 fgets

为了正确解析输入,我需要能够计算文件中的行数。但是,我不想计算只是换行符的行。为此,我创建了以下函数:

int countLinesInFile(char *filename) {
  int newlines = 0;

  if (access(filename,F_OK) != -1)
    error("File not found",0);

  FILE *input = fopen(filename,"r");

  int size = 256 * 4;
  char buffer[size];
  while ((fgets(buffer,sizeof(buffer),input)) != EOF) {
    printf("Read a string");
    if (buffer == "\n")
      continue;
    newlines++;
  }

  fclose(input);
  return newlines;
}

在文件的顶部,我有以下内容:

#include <stdio.h>
#include <unistd.h>

当我运行程序并尝试计算行数时,它会出现分段错误。使用valgrind,我可以看到以下内容:

==6632== Invalid read of size 4
==6632==    at 0x4EA8E6B: fgets (in /usr/lib64/libc-2.24.so)
==6632==    by 0x402219: countLinesInFile (in [executable])
[other information about program, does not seem relevant]
==6632==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==6632== 
==6632== 
==6632== Process terminating with default action of signal 11 (SIGSEGV)
==6632==  Access not within mapped region at address 0x0
==6632==    at 0x4EA8E6B: fgets (in /usr/lib64/libc-2.24.so)
==6632==    by 0x402219: countLinesInFile (in [executable])
[other information about program, does not seem relevant]
==6632==  If you believe this happened as a result of a stack
==6632==  overflow in your program's main thread (unlikely but
==6632==  possible), you can try to increase the size of the
==6632==  main thread stack using the --main-stacksize= flag.
==6632==  The main thread stack size used in this run was 8388608.
==6632== 
==6632== HEAP SUMMARY:
==6632==     in use at exit: 475 bytes in 16 blocks
==6632==   total heap usage: 19 allocs, 3 frees, 3,075 bytes allocated
==6632== 
==6632== LEAK SUMMARY:
==6632==    definitely lost: 0 bytes in 0 blocks
==6632==    indirectly lost: 0 bytes in 0 blocks
==6632==      possibly lost: 0 bytes in 0 blocks
==6632==    still reachable: 475 bytes in 16 blocks
==6632==         suppressed: 0 bytes in 0 blocks
==6632== Rerun with --leak-check=full to see details of leaked memory
==6632== 
==6632== For counts of detected and suppressed errors, rerun with: -v
==6632== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

我试图在while循环的开头添加一行“printf(”读取文件“)”。这段代码没有执行,我相信fgets就是问题所在。不幸的是,我不知道这个问题是什么。

我已经确认我正在尝试阅读的文件中包含正确的文字,并且不是空的。

我创建的函数是否正确执行此任务的方法?如果是这样,我可以遇到什么问题?我将来如何避免这个问题?

更新:这对我来说真的是一个愚蠢的错误。我正在使用Valgrind运行该程序,看起来它不使用可执行文件的目录,这意味着它无法找到该文件。谢谢你的帮助。

5 个答案:

答案 0 :(得分:1)

两件事:首先,只要不再能读取行,fgets就会返回NULL,而不是EOF。因此,条件应为while(fgets(...) != NULL)或短while(fgets(...))。 其次,buffer == "\n"比较两个指向字符的指针,即比较两个存储器地址。并且任何内容都不可能与字符串文字"\n"具有相同的内存地址。因此,比较字符,即buffer[0]=='\n'buffer[0]!='\n'。 我认为您可以轻松摆脱continue - 语句,以便代码如下所示:

  while (fgets(buffer,sizeof(buffer),input)) {
    if (buffer[0] != '\n') {
      newlines++;
    }
  }

答案 1 :(得分:0)

我认为您需要跟踪上一个\n的文件偏移量,如果此\n == last + 1的位置,则不会增加。

答案 2 :(得分:0)

函数fgets返回指针值,失败时返回NULL。 EOF(通常,除非你已经改变它)定义为-1。他们永远不会比较平等,这意味着你应该在你应该停止之后很久就召唤fgets。

答案 3 :(得分:0)

fgets()将您限制为预定义的行长度。要解决这个问题,您可以使用POSIX-standard getline()

在计算行数时,要跳过空行,您只需打折与"\n"匹配的任何内容:

#include <stdio.h>

...

long countLines( const char *filename )
{
    FILE *fp = fopen( filename, "r" );
    if ( fp == NULL )
    {
        return( -1L );
    }

    char *line = NULL;
    size_t bytes = 0UL;
    long lineCount = 0L;

    for ( ;; )
    {
        ssize_t result = getline( &line, &bytes, fp );
        if ( -1 == result )
        {
            break;
        }

        if ( strcmp( line, "\n" ) )
        {
            lineCount++;
        }
    }

    free( line );
    fclose( fp );

    return( lineCount );
}

答案 4 :(得分:-2)

FILE *input = fopen(filename,"r");

应该是

FILE *input;
input = fopen(filename,"r");

我不相信fgets()会返回换行符或EOF。它会在换行符之前停止读取字符,下一个读取将是换行符或连续换行符之后的字符。

您可能需要使用二进制文件读取功能,该功能将立即读取整个文件,然后解析出这些行。这也将处理最后没有EOF的文本文件的情况。许多人没有

  • 获取文件的大小。
  • 分配缓冲区以保存整个文件。
  • 将整个文件读入缓冲区。
  • 解析缓冲区。

C library function - fgets()
C File I/O and Binary File I/O