由于文件 txt 分隔符逗号 C,fscanf 出现问题
Problem with fscanf because of file txt divider comma C
我要用这个文件信息
香烟,吸烟用,1,5.500000
伍兹,对于室内烟囱,2,100.000000
要填充此结构:
typedef struct product{
char name[32];
char about_product[32];
int product_id;
double price;
}sProduct;
使用这个函数:
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);
}
但它不会出错,因为我在 txt 文件中使用逗号作为分隔符。
这里有两个问题,都围绕着 scanf
如何处理 %s
指令:
- 它会扫描以空格分隔的 字符串,因此它会将某些输入数据中的内部空格作为分隔符
- 它扫描 以空格分隔的 字符串,因此它不会将逗号识别为字段分隔符
您可以通过多种方式完成您设置的输入任务,但要继续使用 scanf
将您的特定输入直接扫描到您的数据结构中,您需要 %[
指令而不是 %s
.
%[
指令接受 "scanset" 描述字段中可能出现的字符,其中可以包含空格。这采用类似于正则表达式或 glob 字符 class 的形式。相应的参数应该是指向 char
的指针,就像 %s
指令一样。您还应该知道,与大多数指令(包括 [=14=)不同,%[
指令不会跳过前导空格。对你来说,它的用法可能是这样的:
fscanf(fp, "%[^,],%[^,],%d,%g\n", ptr.name, ptr.about_product, &ptr.product_id, &ptr.price);
那里的两个 %[^,]
字段描述符各自扫描除逗号 (,
) 之外的任意数量的字符。
此外,您最好指定字段宽度,以避免在数据中出现太长的字段时超出数组的范围。由于您提供了 32 字节的数组,并且每个数组中的一个字节必须保留用于字符串终止符,因此可能是这样的:
fscanf(fp, "%31[^,],%31[^,],%d,%g\n", ptr.name, ptr.about_product, &ptr.product_id, &ptr.price);
而且,对于几乎所有具有任何失败模式的函数,您还应该以编程方式检查函数是否成功。您需要主动且始终如一地执行此操作,否则您的程序可能会以微妙且令人惊讶的方式失败。对于 scanf
和许多类似的用法,这意味着检查 return 值是否等于格式中输入指令的数量(return 值表示有多少字段成功扫描并分配):
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 ...
}
附录:
继续您应该检查具有故障模式的函数中的故障这一点,我还观察到另一个这样的函数是 fopen()
。这个函数完全有可能失败,在这种情况下它 return 是一个空指针。一个健壮的程序肯定会检查这种情况并优雅地处理它,使用类似于我为 scanf()
描述的模式。但是,这与您询问的具体不当行为无关。 (归功于@RobertSsupportsMonicaCellio。)
我要用这个文件信息
香烟,吸烟用,1,5.500000
伍兹,对于室内烟囱,2,100.000000
要填充此结构:
typedef struct product{
char name[32];
char about_product[32];
int product_id;
double price;
}sProduct;
使用这个函数:
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);
}
但它不会出错,因为我在 txt 文件中使用逗号作为分隔符。
这里有两个问题,都围绕着 scanf
如何处理 %s
指令:
- 它会扫描以空格分隔的 字符串,因此它会将某些输入数据中的内部空格作为分隔符
- 它扫描 以空格分隔的 字符串,因此它不会将逗号识别为字段分隔符
您可以通过多种方式完成您设置的输入任务,但要继续使用 scanf
将您的特定输入直接扫描到您的数据结构中,您需要 %[
指令而不是 %s
.
%[
指令接受 "scanset" 描述字段中可能出现的字符,其中可以包含空格。这采用类似于正则表达式或 glob 字符 class 的形式。相应的参数应该是指向 char
的指针,就像 %s
指令一样。您还应该知道,与大多数指令(包括 [=14=)不同,%[
指令不会跳过前导空格。对你来说,它的用法可能是这样的:
fscanf(fp, "%[^,],%[^,],%d,%g\n", ptr.name, ptr.about_product, &ptr.product_id, &ptr.price);
那里的两个 %[^,]
字段描述符各自扫描除逗号 (,
) 之外的任意数量的字符。
此外,您最好指定字段宽度,以避免在数据中出现太长的字段时超出数组的范围。由于您提供了 32 字节的数组,并且每个数组中的一个字节必须保留用于字符串终止符,因此可能是这样的:
fscanf(fp, "%31[^,],%31[^,],%d,%g\n", ptr.name, ptr.about_product, &ptr.product_id, &ptr.price);
而且,对于几乎所有具有任何失败模式的函数,您还应该以编程方式检查函数是否成功。您需要主动且始终如一地执行此操作,否则您的程序可能会以微妙且令人惊讶的方式失败。对于 scanf
和许多类似的用法,这意味着检查 return 值是否等于格式中输入指令的数量(return 值表示有多少字段成功扫描并分配):
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 ...
}
附录:
继续您应该检查具有故障模式的函数中的故障这一点,我还观察到另一个这样的函数是 fopen()
。这个函数完全有可能失败,在这种情况下它 return 是一个空指针。一个健壮的程序肯定会检查这种情况并优雅地处理它,使用类似于我为 scanf()
描述的模式。但是,这与您询问的具体不当行为无关。 (归功于@RobertSsupportsMonicaCellio。)