Home > Software design >  Using fgets and sscanf for taking a string from a file
Using fgets and sscanf for taking a string from a file

Time:09-16

i have a file.txt structured this way: author, "title", genre, price, copies_inStock

R. Tolkien, "The lords of the rings", Fantasy, 65.50, 31

i tried using fgets and sscanf

FILE *fp = NULL;
    char string[100];
    char title[30], author[30], genre[30];
    float price;
    int copies=0;
   fp = fopen("text.txt", "r");
   while(!feof(fp)) {
       fgets(string, 100, fp);
       sscanf(string, "%[^,],%[^,],%[^,],%f[^,],%d[^ ]", autore, titolo, genere, &prezzo, &copie);
   }
fclose(fp);
printf("%s %s %s %.2f %d\n", author, title, genre, price, copies);
OUTPUT
R. Tolkien  "The lord of the rings"  fantasy 65,50 0

Why it don't access to the variable copies? There are better ways? Thanks

CodePudding user response:

The format specifiers on this line are incorrect

sscanf(string, "%[^,],%[^,],%[^,],%f[^,],%d[^ ]", autore, titolo, genere, &prezzo, &copie);

It should be

sscanf(string, "%[^,], %[^,], %[^,],%f,%d", autore, titolo, genere, &prezzo, &copie);

The additional spaces are to filter leading whitespace - it is not automatic with %[] (or with %c).

The %f and %d were a sort of mangled hybrid of what they should be. The conversion of those stops at the first character that cannot be used, without your intervention.

Side note: you really must check the result of scanf() function family: the number of successful conversions made.

CodePudding user response:

"%f[^,]" is legal, yet certainly not what OP wants.

"%f" scans for a float, then "[^,]" scans for that 4 character sequence.


There are better ways?

Use " %n" to check scanning success. It records the offset of the scan.
Use width limits like 29 in )[^,] to not overfill the char array.
Use a space before )[^,] to consume optional leading whitespace.
Money is always tricky.
Do not use while(!feof(fp)). Check return from fgets().

char string[100];
char title[30], author[30], genre[30];
double price;
int copies;
FILE *fp = fopen("text.txt", "r");

if (fp) {
  while(fgets(string, sizeof string, fp)) {
    int n = 0;
    sscanf(string, " )[^,], )[^,], )[^,],%lf ,%d %n", 
        author, title, genre, &price, &copies, &n);
    // If n==0, scan was incomplete
    // If string[n], string has extra garbage
    if (n == 0 || string[n]) {
      fprintf(stderr, "Bad <%s>\n", string);
    } else {
      printf("%s %s %s %.2f %d\n", author, title, genre, price, copies);
      // Robust code here would do additional work: 
      // Trim trailing string whitespace.  Range checks on numeric values, etc.
    }
  }
  fclose(fp);
}
  • Related