今天我查看了一些从文本文件中解析数据的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
检查删除序列怎么样?
答案 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...
请注意,10
为sizeof(records->bday) - 1
,但您无法将长度作为sscanf()
的参数提供;它必须按字面意思出现在格式字符串中。在这里,您可以使用奇怪的大小,但如果您正在处理更通用的代码,您可能会想到:
sprintf(format, "%%%zus", sizeof(records->bday) - 1);
第一个%%
映射到%
; %zu
格式的大小(z
是size_t
的C99; s
用于在使用格式时进行字符串转换。
或者您可以考虑使用strcpy()
或memcpy()
或memmove()
将输入字符串的右侧子部分复制到结构中 - 但请注意%10s
会跳过前导空格strcpy()
等人不会。当然,你必须知道在进行复制之前字符串的长度,并确保字符串为空终止。