简体   繁体   English

由于文件 txt 分隔符逗号 C 而导致 fscanf 出现问题

[英]Problem with fscanf because of file txt divider comma C

I have to use this file information我必须使用这个文件信息
Cigaretas,For Smoking,1,5.500000香烟,吸烟用,1,5.500000
Woods,For indor chimneys,2,100.000000伍兹,用于室内烟囱,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:使用这个 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.但它没有错误,因为我在 txt 文件中使用逗号作为分隔符。

There are two issues here, both revolving around how scanf processes %s directives:这里有两个问题,都围绕scanf如何处理%s指令:

  • 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 .有几种方法可以 go 关于您设置的输入任务,但要继续使用scanf将您的特定输入直接扫描到数据结构中,您需要%[指令而不是%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.这采用类似于正则表达式或全局字符 class 的形式。 The corresponding argument should be a pointer to char , just as for a %s directive.对应的参数应该是指向char的指针,就像%s指令一样。 You should also be aware that unlike most directives, including %s , the %[ directive does not skip leading whitespace.您还应该知道,与大多数指令(包括%s )不同, %[指令不会跳过前导空格。 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:由于您提供了 32 字节的 arrays,并且每个字节必须为字符串终止符保留一个字节,因此可能是这样的:

        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.而且,与几乎所有具有任何故障模式的功能一样,您还应该以编程方式检查function 是否成功。 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):对于scanf和许多类似的使用,这意味着检查返回值是否等于格式中输入指令的数量(返回值表示成功扫描和分配了多少字段):

        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() .继续您应该检查具有故障模式的函数中的故障,我还观察到另一个这样的 function 是fopen() It is entirely possible for this function to fail, in which case it returns a null pointer.这个 function 完全有可能失败,在这种情况下,它会返回一个 null 指针。 A robust program would definitely check for this case and handle it gracefully, using a pattern similar to the one I described for scanf() .一个健壮的程序肯定会检查这种情况并优雅地处理它,使用类似于我为scanf()描述的模式。 This, however, is not related to the specific misbehavior you asked about.但是,这与您询问的具体不当行为无关。 (Credit to @RobertSsupportsMonicaCellio.) (归功于@RobertSsupportsMonicaCellio。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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