使用fscanf()输出无效

时间:2012-06-26 03:14:58

标签: c scanf

我使用的语言是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

stdout中显示的结果是:

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

显然,结果有一条额外的线路无处可去。有人知道这会怎么样吗? THX!

3 个答案:

答案 0 :(得分: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,然后与数据同步,直到最后一行。格式末尾的换行符(就像格式字符串中的任何其他空格一样)会占用空白区域,这就是为什么尽管前导空白但最后一行仍然有效。

答案 1 :(得分:1)

  

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

     

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

     

除非指定,否则从流中读取输入项   包括一个n说明符。

     

[...]

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

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

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

" %c %lx,%d\n"

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

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

" %c %lx,%d"

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

答案 2 :(得分:0)

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

然后它会打印一个空格,然后在addressobjsize声明时发生

编辑 -

fscanf在每次通话后消耗空白,如果你打电话给ftell,你会看到

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