简体   繁体   中英

Printing number of lines in a file without using fgets

So I am trying to print the number of lines in a file. The catch is that I cannot use fgets. Is there any other alternative to this which involves only fscanf? I tried running the following:

while (1) {
  ret = fscanf(fin, "%[^\n]", string);
  if (ret == EOF) break;
  line_count++;
}

But it does not work. It is giving me an infinite loop. Can anyone please tell me what the issue is ?

this statement:

ret = fscanf(fin, "%[^\n]", string);

should be:

ret = fscanf(fin, " %[^\n]", string);

Notice the leading space, which will consume any leading 'white space'

I agree with the comments about newlines. Therefore, suggest:

size_t lineCount = 0;
int ch;
while( ( ch = getchar() ) != EOF )
{
    if( '\n' == ch )
    {
        lineCount++;
    }
}

You must also be aware of a corner-case not covered by the other answers. For a file to be POSIX compliant, the final character must be a '\\n' character, or the file may be empty to begin with. For example, a two line file that contains a POSIX end-of-file could be:

my dog has fleas\n
my cat has none\n

If you were counting lines in the file above by counting the number of '\\n' characters, your number of lines for the file would be as expected -- 2 . However, there are many editors today, that do no create POSIX compliant files because they fail to write the final '\\n' after the last line of text. So many editors would leave the file as:

my dog has fleas\n
my cat has none

It is a perfectly legal way to save the file, it is just a non-POSIX way of doing so. Now, what would your program output if you were simply counting the '\\n' characters to determine the lines in the file? ( 1 -- you would count one-too-few lines)

To address the issue of a non-POSIX eof to ensure your line count is correct either way, you need to check the last character before EOF and see if it was a '\\n' , and if it wasn't you need to add +1 to your line count.

You can do that fairly simply just by saving the current character at the end of you loop so that it is preserved for comparison after EOF is encountered. You can do something like the following:

/* count lines in file from open file-stream.
 * returns number of lines in file, including files
 * with non-POSIX end-of-file.
 */
size_t linecount (FILE *fp)
{
    int c, last = 0;                    /* current and last char read */
    size_t nlines = 0;                  /* line counter */
    
    rewind(fp);                         /* prevent UB if EOF already set on fp */
    
    while ((c = fgetc(fp)) != EOF) {    /* loop reading each char */
        if (c == '\n')                  /* if '\n' increment line counter */
            nlines++;
        last = c;                       /* save current as last */
    }
    /* if not empty-file and not POSIX eof, add 1 to nlines */
    return last && last != '\n' ? nlines + 1 : nlines;
}

The loop can also be written as:

    do {
        last = c;
        if ((c = fgetc(fp)) == '\n')
            nlines++;
    } while (c != EOF);

Look things over and let me know if you have further questions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM