1

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Rohit Soni
  • 23
  • 1
  • 5
  • Don't leave a trailing space in the format string if you might use it interactively (with you typing at the keyboard). – Jonathan Leffler Dec 17 '16 at 22:52
  • Rule 1 about f/scanf: always check the return value. Rule 2 about f/scanf: don't try to use them for anything complicated. Rule 3 about f/scanf: as soon as you're comfortable enough with C to do so, learn how to read lines using `fgets`, and parse lines into tokens some other way, so that you will never have to use f/scanf again, because: Rule 4 about f/scanf: they're really not good for much. – Steve Summit Dec 17 '16 at 22:57

1 Answers1

3

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
Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • `if (f == 0)`, wow, I didn't know you could do that. Cool, nice answer. – RoadRunner Dec 18 '16 at 03:42
  • Thank you so much Jonathan , But I'm having a little doubt regarding %127[^0-9] why you have written 127 here and didn't even wrote 's' (as we are accepting a string)? – Rohit Soni Dec 18 '16 at 05:14
  • 1
    See the link under 'buffer overflow' for why 127 is appropriate. As I said in the answer, `%[…]` is a conversion specifier on its own; it is not a modifier for `%s`. – Jonathan Leffler Dec 18 '16 at 05:18