1

I'm trying to read a file line by line and count the characters of each line. Those line might contains space characters and I need also to count them. I'm only allowed to use feof and scanf functions.

Sample Code

...
while(!feof(stdin)){
    char inputLineArray[1000];
    scanf("%[^\n]s", inputLineArray);
    printf(inputLineArray);
}
...

My sample file is a txt file which contains the following content:

hello world
abcdsdsdsdsd

But after it prints:

hello world

My program is stuck into infinite loop which does nothing.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
kluo
  • 131
  • 1
  • 10

2 Answers2

0

From man 3 scanf:

The scanf() family of functions scans input according to format as described below.

This means that your provided pattern %[^\n]s (don't match newlines) will stop matching after world because there is a newline. You'd need to skip to the next char in the stream.

There are many questions like yours on Stackoverflow, search for scanf infinite loop.

RedX
  • 14,749
  • 1
  • 53
  • 76
0

scanf("%[^\n]s", inputLineArray); is incorrect and inappropriate:

  • the conversion specifier does not have a trailing s, it is just %[^\n] ;
  • scanf reads the stream and stores any characters before the newline into inputLineArray and leaves the newline pending in the stream ;
  • scanf should be given the maximum number of characters to store to avoid undefined behavior on long lines: scanf("%999[^\n]", inputLineArray) ;
  • you should test the return value of scanf() to determine if the conversion was successful. The test while (!feof(stdin)) is pathologically inappropriate: Why is “while ( !feof (file) )” always wrong? ;
  • you would then see another problem: this conversion fails on empty lines because there are no characters to store into the destination array, and since scanf() leaves the newline pending, the second call fails and all successive ones too.

Note also that it is highly risky to call printf with user supplied data as a format string. The behavior is undefined if the line contains non trivial format specifications.

Here is a better way to read the file line by line:

#include <stdio.h>
#include <string.h>

...

    char inputLineArray[1001];
    while (fgets(inputLineArray, sizeof inputLineArray, stdin)) {
        buf[strcspn(buf, "\n")] = '\0';  // strip the trailing newline if present
        printf("%s\n", inputLineArray);
    }

...

Note however that input lines with 1000 bytes or more will be broken into multiple output lines.

scanf() is not the right tool for your purpose, indeed it is full of quirks and shortcomings, but if you are required to use scanf(), here is a corrected version:

    char inputLineArray[1000];
    while (scanf("%c", &inputLineArray[0]) == 1) {
        /* one byte was read, check if it is a newline */
        if (inputLineArray[0] == '\n') {
            /* empty line must be special cased */
            inputLineArray[0] = '\0';
        } else {
            /* set the null terminator in case the next `scanf` fails */
            inputLineArray[1] = '\0';
            /* attempt to read the rest of the line */
            scanf("%998[^\n]", inputLineArray + 1);
            /* consume the pending newline, if any */
            scanf("%*1[\n]");
        }
        printf("%s\n", inputLineArray);
    }
    if (feof(stdin)) {
        /* scanf() failed at end of file, OK */
    } else {
        printf("read error\n");
    }

Note that feof() is not used as scanf("%c", ...) will return EOF at end of file, so the while() loop with stop as expected.

feof() is only used to distinguish end of file from read error conditions in stream I/O. Most C programs do not need to distinguish between these as read errors can be handled the same way as truncated input files. This function is almost always used incorrectly. In short, you should never use feof(), nor other error-prone or deprecated functions such as gets() and strncpy(). Be also very careful with sprintf(), strcpy(), strcat()...

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Using `feof()` is definitely the wrong approach. I am afraid your teacher is not giving you good advice. – chqrlie Sep 18 '18 at 06:17
  • If I have to use feof(), is there any way to fix it to make it read empty line? – kluo Sep 18 '18 at 18:22
  • You do not *have to* use `feof()`, if you teacher requires such use, you can test whether `scanf()` failed at end of file, as expected, or if some other condition caused the failure, such as a read error, which is quite unlikely. I'm afraid your teacher expects something else, such as the pathological mistake in your posted code, which is a pity but probably not something you can correct at your level. You could ask him to comment this popular question on SO: https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong – chqrlie Sep 19 '18 at 14:42