【问题标题】:Invalid output with fscanf()fscanf() 的输出无效
【发布时间】:2012-06-26 03:14:58
【问题描述】:

我使用的语言是 C 我正在尝试从文件中扫描数据,代码段如下:

char lsm;
long unsigned int address;
int objsize;
while(fscanf(mem_trace,"%c %lx,%d\n",&lsm,&address,&objsize)!=EOF){
    printf("%c %lx %d\n",lsm,address,objsize);
}

我读取的文件的第一行如下:

 S 00600aa0,1
I  004005b6,5
I  004005bb,5
I  004005c0,5
 S 7ff000398,8

在标准输出中显示的结果是:

  8048350 134524916
S 600aa0 1
I 4005b6 5
I 4005bb 5
I 4005c0 5
S 7ff000398,8

显然,结果有一个额外的行,没有任何地方出现。有没有人知道这是怎么发生的? 谢谢!

【问题讨论】:

    标签: c scanf


    【解决方案1】:

    这适用于您提供的数据:

    #include <stdio.h>
    
    int main(void)
    {
        char lsm[2];
        long unsigned int address;
        int objsize;
        while (scanf("%1s %lx,%d\n", lsm, &address, &objsize) == 3)
            printf("%s %9lx %d\n", lsm, address, objsize);
        return 0;
    }
    

    有多个变化。最简单、影响最小的就是从fscanf() 更改为scanf();这是为了我的方便。

    一个重要的变化是lsm 的类型从单个char 变为两个字符的数组。格式字符串然后使用 %1s 将一个字符(加上 NUL '\0')读入字符串,但它也(这是至关重要的)跳过前导空格。

    另一个变化是在条件中使用== 3 而不是!= EOF。如果出现问题,scanf() 返回成功匹配的数量。假设它读到了一个字母,但后面不是一个十六进制数字;它会返回 1(不是 EOF)。此外,它会在每次迭代中返回 1,直到找到与十六进制数匹配的内容。始终测试您期望的值的数量。

    使用%9lx 整理了输出格式。我在 64 位系统上进行测试,所以 9 位十六进制转换得很好。 scanf() 的一个问题是,如果您在转换时出现溢出,则行为未定义。

    输出:

    S    600aa0 1
    I    4005b6 5
    I    4005bb 5
    I    4005c0 5
    S 7ff000398 8
    

    你为什么得到你得到的结果?

    第一次转换将空格读入lsm,但随后未能将S 转换为十六进制数,因此将其留给下一个循环。因此,您在地址和对象大小列中打印了剩余的垃圾。第二次迭代读取S,然后与数据同步直到最后一行。格式末尾的换行符(就像格式字符串中的任何其他空白一样)会占用空白,这就是为什么最后一行尽管有前导空白仍然有效。

    【讨论】:

      【解决方案2】:

      作为转换规范的指令定义了一组 匹配输入序列,如下文针对每个说明符所述。一种 转换规范按以下步骤执行:

      输入空白字符(由 isspace 函数指定) 被跳过,除非规范包含 [、c 或 n 说明符。

      从流中读取输入项,除非规范 包括一个 n 说明符。

      [...]

      第一次调用 fscanf 时,您的 %c 会读取文件中的第一个空格。您的空白字符读取零个或多个空白字符,这次是零个。您的 %lx 无法匹配文件中的 S 字符,因此 fscanf 返回。你不检查结果。您的变量包含它们从早期操作中获得的值。

      第二次调用 fscanf 时,%c 读取文件中的第一个 S 字符。从那时起,其他一切也都成功了。

      在编辑中添加,这是解决您问题的最简单的格式字符串更改:

      " %c %lx,%d\n"
      

      开头的空格将读取零个或多个空白字符,然后 %c 将读取文件中的第一个非空白字符。

      这是另一个格式字符串,也可以解决您的问题:

      " %c %lx,%d"
      

      原因是如果连续两次读取并丢弃零个或多个空白字符,结果与只执行一次相同。

      【讨论】:

        【解决方案3】:

        我认为 fsanf 将第一个字符 [空格] 读入 lsm 然后无法读取 addressobjsize,因为格式转换与该行的其余部分不匹配。

        然后它打印一个空格,然后在声明时打印addressobjsize 中的任何内容

        编辑--

        fscanf 在每次调用后使用空格,如果你调用 ftell 你会看到

        printf("%c %lx %d %d\n",lsm,address,objsize,ftell(mem_trace));
        

        【讨论】:

        • 您的回答似乎是对的。但它只发生在文件的开头。因为文件的其余部分也有一行以空格开头,但输出似乎没问题
        • 好吧,在你发布该行之前的输出停止
        • @shirley fscanf 在每次调用后使用空格,如果你调用 ftell 你会看到
        猜你喜欢
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 2014-05-18
        • 2016-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-17
        相关资源
        最近更新 更多