Read integer after reading a string from a file using fscanf

2.1k views Asked by At

I've made a program which has test.txt file which contains following

24 Rohit Soni 1997

This is my code:

#include <stdio.h>

void main()
{
    FILE *f;
    int no,i;
    char *name;
    f=fopen("test.txt","r");
    fscanf(f,"%d %[^[0-9]]s %d ",&no, name, &i);
    printf("%d %s %d",no, name,i);
    fclose(f);
}

But it is not showing the correct output. Output is:

24 Rohit Soni 12804

Please tell me what to do. Why is it not accepting an integer after taking string from fscanf using %[ format specifier.

1

There are 1 answers

3
Jonathan Leffler On BEST ANSWER

You should test the return code from fscanf(); it would tell you 2 values are converted instead of the 3 you expected. You should always test the return code from fscanf(), usually for the expected number of conversions and only very seldom will you test for EOF or 0.

The problem is that a scan set %[^…] is not a modifier for %s, and also the scan set stops at the first ] unless that immediately follows the [ for a regular scan set or [^ for a negated scan set. So, your format string is looking for a sequence of 'not a digit nor an [' characters, followed by a ] and an s — and it isn't finding the ] and s in the input.

You need:

#include <stdio.h>

int main(void)
{
    const char *filename = "test.txt";
    FILE *f = fopen(filename, "r");
    if (f == 0)
    {
        fprintf(stderr, "Failed to open '%s' for reading\n", filename);
        return 1;
    }
    int no,i;
    char name[128];

    if (fscanf(f, "%d %127[^0-9] %d", &no, name, &i) != 3)
    {
        fprintf(stderr, "Failed to read three values\n");
        return 1;
    }
    printf("%d [%s] %d\n", no, name, i);
    fclose(f);
    return 0;
}

You need to check that fopen() worked. The error message should include the file name that you failed to open. (If you paid attention to command line arguments — using int main(int argc, char **argv) — you would report the program name from argv[0] in the error messages too.) You need to allocate space for name rather than use an uninitialized pointer. The correct return type for main() is int — though Microsoft does allow void. Note that the input format ensures there is no buffer overflow.

I've enclosed the name in […] in the output so you can see that the name includes the trailing space. The output I get is:

24 [Rohit Soni ] 1997