Trouble reading a line using fscanf()

I'm trying to read a line using the following code:

while(fscanf(f, "%[^\n\r]s", cLine) != EOF )
{
    /* do something with cLine */
}

But somehow I get only the first line every time. Is this a bad way to read a line? What should I fix to make it work as expected?


Solution 1:

It's almost always a bad idea to use the fscanf() function as it can leave your file pointer in an unknown location on failure.

I prefer to use fgets() to get each line in and then sscanf() that. You can then continue to examine the line read in as you see fit. Something like:

#define LINESZ 1024
char buff[LINESZ];
FILE *fin = fopen ("infile.txt", "r");
if (fin != NULL) {
    while (fgets (buff, LINESZ, fin)) {
        /* Process buff here. */
    }
    fclose (fin);
}

fgets() appears to be what you're trying to do, reading in a string until you encounter a newline character.

Solution 2:

If you want read a file line by line (Here, line separator == '\n') just make that:

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

int main(int argc, char **argv)
{
        FILE *fp;
        char *buffer;
        int ret;

        // Open a file ("test.txt")
        if ((fp = fopen("test.txt", "r")) == NULL) {
                fprintf(stdout, "Error: Can't open file !\n");
                return -1;
        }
        // Alloc buffer size (Set your max line size)
        buffer = malloc(sizeof(char) * 4096);
        while(!feof(fp))
        {
                // Clean buffer
                memset(buffer, 0, 4096);
                // Read a line
                ret = fscanf(fp, "%4095[^\n]\n", buffer);
                if (ret != EOF) {
                        // Print line
                        fprintf(stdout, "%s\n", buffer);
                }
        }
        // Free buffer
        free(buffer);
        // Close file
        fclose(fp);
        return 0;
}

Enjoy :)

Solution 3:

If you try while( fscanf( f, "%27[^\n\r]", cLine ) == 1 ) you might have a little more luck. The three changes from your original:

  • length-limit what gets read in - I've used 27 here as an example, and unfortunately the scanf() family require the field width literally in the format string and can't use the * mechanism that the printf() can for passing the value in
  • get rid of the s in the format string - %[ is the format specifier for "all characters matching or not matching a set", and the set is terminated by a ] on its own
  • compare the return value against the number of conversions you expect to happen (and for ease of management, ensure that number is 1)

That said, you'll get the same result with less pain by using fgets() to read in as much of a line as will fit in your buffer.

Solution 4:

Using fscanf to read/tokenise a file always results in fragile code or pain and suffering. Reading a line, and tokenising or scanning that line is safe, and effective. It needs more lines of code - which means it takes longer to THINK about what you want to do (and you need to handle a finite input buffer size) - but after that life just stinks less.

Don't fight fscanf. Just don't use it. Ever.