我知道%d
格式说明符在fscanf()
中使用时会读取一个整数并忽略它前面的空格,包括换行符(我验证了它)。但在我的关注中使用fscanf()
从多行的文件中读取每个3个整数的程序,格式字符串"%d%d%d%*c"
与"%d%d%d"
一样好。
为什么会这样?由于fscanf()
与%d
一起用作格式说明符字符串中的第一个格式说明符,忽略整数前面的任何空格,为什么不加{{1}用作最后一个说明符导致任何错误或副作用?如果%*c
说明符在一行中每组3个数字之后没有忽略换行符,那么%d
就会有意义离开换行符。但是,即使%*c
默认忽略fscanf()
的空格,它为什么没有错误或副作用? 当%* c找不到要吃的字符并且说明符和输入之间不匹配时,不应该fscanf()停止扫描吗?当%d
发生不匹配时,Isn&#t; t fscanf()
应该停止吗?
编辑:如果我使用scanf()
,它甚至可以正常工作!! 一旦格式说明符不匹配,后续字符的扫描和处理就不会停止并在开头输入?
"%*c%d%d%d"
以下是我的文件#include <stdio.h>
#include <stdlib.h>
int main ()
{
int n1,n2,n3;
FILE *fp;
fp=fopen("D:\\data.txt","r");
if(fp==NULL)
{
printf("Error");
exit(-1);
}
while(fscanf(fp,"%d%d%d%*c",&n1,&n2,&n3)!=EOF) //Works as good as line below
//while(fscanf(fp,"%d%d%d",&n1,&n2,&n3)!=EOF)
printf("%d,%d,%d\n",n1,n2,n3);
fclose(fp);
}
中的数据格式:
data.txt
输出:
243 343 434
393 322 439
984 143 943
438 243 938
答案 0 :(得分:3)
考虑问题中程序的这种变化:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char *file = "D:\\data.txt";
FILE *fp;
char *formats[] =
{
"%d%d%d%*c",
"%d%d%d",
"%*c%d%d%d",
};
if (argc > 1)
file = argv[1];
for (int i = 0; i < 3; i++)
{
if ((fp = fopen(file, "r")) == 0)
{
fprintf(stderr, "Failed to open file %s\n", file);
break;
}
printf("Format: %s\n", formats[i]);
int n1,n2,n3;
while (fscanf(fp, formats[i], &n1, &n2, &n3) == 3)
printf("%d, %d, %d\n", n1, n2, n3);
fclose(fp);
}
return 0;
}
重复打开效率不高,但这不是一个问题。清晰度和显示行为更为重要。
写入(a)使用命令行中指定的文件名,因此我不必使用D:\data.txt
之类的名称,这些名称在Unix系统上创建非常不方便,并且( b)显示正在使用的三种格式。
给出问题的数据文件:
243 343 434
393 322 439
984 143 943
438 243 938
该计划的输出是:
Format: %d%d%d%*c
243, 343, 434
393, 322, 439
984, 143, 943
438, 243, 938
Format: %d%d%d
243, 343, 434
393, 322, 439
984, 143, 943
438, 243, 938
Format: %*c%d%d%d
43, 343, 434
393, 322, 439
984, 143, 943
438, 243, 938
请注意,当%*c
格式的第一部分时,第一个数字的第一个数字将被消耗。读取前3个数字后,%*c
读取行上第三个数字后的换行符,然后%d
跳过更多空格(除非没有任何数字)并读取数字
否则,行为在下面的评论中有所阐述,很大程度上取决于另一个相关问题。
相关问题Use fscanf()
to read from given line中正在讨论的一些代码是:
fscanf(f, "%*d %*d %*d%*c");
fscanf(f, "%d%d%d", &num1, &num2, &num3);
我注意到代码应该测试fscanf()
的返回值。但是,使用三个%*d
转换规范,如果在到达指定行之前遇到EOF,则可能会得到EOF的返回值。不幸的是,在您执行第二行fscanf()
之前,您无法知道第一行包含字母而不是数字。你也应该测试第二个fscanf()
;您可能会获得EOF,或0或1或2(所有这些都表示存在问题),或者您可能会获得3表示3次转换成功。请注意,在格式中添加\n
意味着将跳过空行,但无论如何都会发生这种情况。 %d
将空格跳到第一个数字。
我们还有其他任何方式可以阅读,但忽略了我对
fscanf(f,"%*d%*d%*d")
笨拙地做过的整行吗?使用%*[^\n]
是否可以为此做最近的事情?
跳过整行的最佳方法是使用fgets(),就像我answer中代码的最后一个版本一样。显然,如果这些行中的任何一行超过4095字节,那么它会错误计算行数。 OTOH,这是不太可能的。
我现在感到困惑,我不想把它放在一个问题中。所以你能告诉我这个 -
fscanf()
自动忽略空格,所以在第一行之后,根据我的%*d%*d%*d
说明符读取和忽略三个整数时,我希望fscanf()
忽略换行符当它在循环的下一次运行中开始读取时也是如此。但是,为什么我的其他%*c
或\n
会导致问题,并且在我的代码中使用%*d%*d%*d%*c
或%*d%*d%*d\n
时程序运行正常?
你不能告诉那些格式出了什么问题;您可以检测到EOF,但除此之外,fscanf()
将返回0.但是,由于%*d
跳过前导空格 - 包括换行符 - 在第三个之后是否读取换行符并不重要%*c
与否\n
的号码,当你在那里\n
时,这是一个空格,因此读取会跳过换行符和任何尾随或前导空白区域,当它到达非空格时停止白色空间字符。当然,您也可以在三个数字的中间添加换行符,或者您可以在一行中包含三个以上的数字。
请注意,当用户在终端上键入时,格式中的尾随fscanf()
特别奇怪。用户点击返回,并继续点击返回,但程序不会继续,直到用户键入非空白字符。这就是当数据不可靠时fgets()
如此难以使用的原因。当它可靠时,它很容易,但如果出现任何问题,诊断和恢复都会很痛苦。这就是为什么最好使用sscanf()
和%c
;如果你愿意,你可以控制正在解析的内容,你可以使用不同的格式再试一次,然后你可以报告整行,而不仅仅是fscanf()无法解释的内容。
请注意,%*c
(和%*c
)不会跳过空格;因此,格式末尾的%[...]
读取(并丢弃)读取后的字符后的字符。如果这是换行符,则表示读取并忽略该字符。扫描集{{1}}是另一个不跳过空格的转换规范;所有其他标准转换规范都会跳过前导空格。
答案 1 :(得分:1)
fscanf()成功后,该函数返回成功填充的参数列表的项数。由于匹配失败,读取错误或文件结束的范围,此计数可以匹配预期的项目数或更少(甚至为零)。
上面的para永远不会讨论停止错配。它也会尝试额外的说明符,因为没有输入所以它只返回成功扫描的数字。如果格式规范的参数太多,则忽略额外的参数。如果格式规范没有足够的参数,则结果未定义。