使用fscanf()读取每行3个数字的文件,为什么“%d%d%d%* c”与“%d%d%d”一样好?

时间:2013-05-15 06:09:16

标签: c newline scanf format-specifiers

我知道%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

2 个答案:

答案 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永远不会讨论停止错配。它也会尝试额外的说明符,因为没有输入所以它只返回成功扫描的数字。如果格式规范的参数太多,则忽略额外的参数。如果格式规范没有足够的参数,则结果未定义。