fgets与sscanf相结合

时间:2011-12-18 12:34:05

标签: c algorithm data-structures stream

今天我查看了一些从文本文件中解析数据的C代码 我偶然发现了这些行

fgets(line,MAX,fp);
if(line[strlen(line)-1]=='\n'){
    line[strlen(line)-1]='\0');
}else{
    printf("Error on line length\n");
    exit(1);
}
sscanf((line,"%s",records->bday));

记录是结构

typedef struct {
    char bday[11];
}record;

所以这里我的问题是关于fgets-sscanf组合来创建一个类型/长度安全的流阅读器:

  • 除了必须将这两个读者合并之外,还有其他方法可以解决这个问题吗?

  • \n检查删除序列怎么样?

1 个答案:

答案 0 :(得分:2)

fgets()sscanf()的组合通常很好。但是,您应该使用:

if (fgets(line, sizeof(line), fp) != 0)
{
    ...
}

检查I / O错误和EOF。它还假设数组的定义是可见的(否则sizeof给出指针的大小,而不是数组的大小)。如果数组不在范围内,则应该将数组的大小传递给包含此代码的函数。所有这一切,都比使用MAX代替sizeof(line)更糟糕。

您尚未检查零长度生日字符串;你可能最终会对输入的字符串进行大量的验证(日期变幻无常且难以处理)。

鉴于MAX为60,但sizeof(records->bday) == 11,您需要保护自己免受sscanf()中的缓冲区溢出的影响。一种方法是:

if (sscanf(line, "%10s", records->bday) != 1)
    ...handle error...

请注意,10sizeof(records->bday) - 1,但您无法将长度作为sscanf()的参数提供;它必须按字面意思出现在格式字符串中。在这里,您可以使用奇怪的大小,但如果您正在处理更通用的代码,您可能会想到:

sprintf(format, "%%%zus", sizeof(records->bday) - 1);

第一个%%映射到%; %zu格式的大小(zsize_t的C99; s用于在使用格式时进行字符串转换。

或者您可以考虑使用strcpy()memcpy()memmove()将输入字符串的右侧子部分复制到结构中 - 但请注意%10s会跳过前导空格strcpy()等人不会。当然,你必须知道在进行复制之前字符串的长度,并确保字符串为空终止。