简体   繁体   中英

Problem with fscanf because of file txt divider comma C

I have to use this file information
Cigaretas,For Smoking,1,5.500000
Woods,For indor chimneys,2,100.000000

To fill this structure:

typedef struct product{
    char name[32];
    char about_product[32];
    int product_id;
    double price;
}sProduct;

Using this function:

void print_prod(){
    sProduct ptr;
    FILE *fp=fopen("product.txt", "r");
    int cnt=1;
    do{
        fscanf(fp, "%s,%s,%d,%g\n", ptr.name, ptr.about_product, &ptr.product_id, &ptr.price);
        cnt++;
    }while(!feof(fp));  
    fclose(fp);
}

But it doesn't bugs because I use comma for a divider in the txt file.

There are two issues here, both revolving around how scanf processes %s directives:

  • it scans whitespace-delimited strings, so it takes the internal whitespace in some of your input data as delimiters
  • it scans whitespace-delimited strings, so it does not recognize the comma as a field delimiter

There are several ways you could go about the input task you have set, but to continue to use scanf to scan your particular input directly into your data structure, you want the %[ directive instead of %s .

The %[ directive accepts a "scanset" describing exactly which characters may appear in the field, which can include whitespace. This takes a form similar to a regex or glob character class. The corresponding argument should be a pointer to char , just as for a %s directive. You should also be aware that unlike most directives, including %s , the %[ directive does not skip leading whitespace. For you, its use might look like this:

        fscanf(fp, "%[^,],%[^,],%d,%g\n", ptr.name, ptr.about_product, &ptr.product_id, &ptr.price);

The two %[^,] field descriptors there each scan any number of characters other than a comma ( , ).

Additionally, you would be wise to specify field widths, so as to avoid overrunning your arrays' bounds in the event that too-long fields appear in your data. Since you provide 32-byte arrays, and one byte of each must be reserved for a string terminator, that could be this:

        fscanf(fp, "%31[^,],%31[^,],%d,%g\n", ptr.name, ptr.about_product, &ptr.product_id, &ptr.price);

But also, as with substantially all functions that have any failure modes, you should also check , programmatically, whether the function succeeded. You need to do this proactively and consistently, else your programs may fail in subtle and surprising ways. For this use of scanf , and many similar ones, that means checking that the return value is equal to the number of input directives in the format (the return value indicates how many fields were successfully scanned and assigned):

        int fields;
        fields = fscanf(fp, "%31[^,],%31[^,],%d,%g\n", ptr.name, ptr.about_product,
                &ptr.product_id, &ptr.price);
        if (fields != 4) {
            // handle input error ...
        }

Addendum:

Continuing with the point that you should check for failures in functions that have failure modes, I also observe that another such function is fopen() . It is entirely possible for this function to fail, in which case it returns a null pointer. A robust program would definitely check for this case and handle it gracefully, using a pattern similar to the one I described for scanf() . This, however, is not related to the specific misbehavior you asked about. (Credit to @RobertSsupportsMonicaCellio.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM