通常fscanf,当使用 扫描非整数时%d,将失败,直到从输入流中显式删除非整数字符。尝试扫描a123失败,直到a从输入流中删除。
尝试扫描------123失败(fscanf返回0),但-已从输入流中删除。
这是正确的行为吗fscanf?
该文件包含----------123此代码的结果:
#include <stdio.h>
int main(void) {
int number = 0;
int result = 0;
FILE *pf = NULL;
if (NULL != (pf = fopen("integer.txt", "r"))) {
while (1) {
if (1 == (result = fscanf(pf, "%d", &number))) {
printf("%d\n", number);
} else {
if (EOF == result) {
break;
}
printf("result is %d\n", result);
}
}
fclose(pf);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
是:
result is 0
result is 0
result is 0
result is 0
result is 0
result is 0
result is 0
result is 0
result is 0
-123
Run Code Online (Sandbox Code Playgroud)
如果文件包含a123结果则为无限循环。
在我看来,这是不一致的行为。不?
这里的重点不是不一致,而是家庭的诸多限制之一fscanf()。
fscanf()该标准对于如何解析输入非常具体。从输入中一一获取字符,并根据格式字符串进行检查。如果它们匹配,则从输入中取出下一个字符。如果它们不匹配,则该字符将被“放回”,并且转换失败。
但只有最后读取的字符才会被放回。
C11 7.21.6.2 fscanf 函数,第 9 段(强调我的):
输入项被定义为最长的输入字符序列,该序列不超过任何指定的字段宽度,并且是匹配的输入序列或者是 的前缀。285)输入项之后的第一个字符(如果有)保持未读状态。
- fscanf 最多将一个输入字符推回输入流。因此,有些序列对strtod、strtol等可接受,但对fscanf则不可接受。
推回这一特性与保证的推回一特性无关ungetc()——它是独立的并且除此之外。(用户可能会fscanf()失败,然后是ungetc()一个字符,并期望ungetc()'d 字符从输入中出现,然后是失败的推回的字符fscanf()。*库函数可能不会调用ungetc(),这是为用户保留的。)
这使得扫描的实施变得fscanf()更加容易,但也会在某些字符序列的中间fscanf()失败,而不会实际回溯到开始转换尝试的位置。
对于您的情况,"--123"请阅读"%d":
'-'。符号。一切都好,继续。'-'。匹配错误。'-'。'-'无法按照上述方式放回第二个。0(转换失败)。这是您不应该在可能存在格式错误的输入上使用的原因(之一)*scanf():扫描可能会失败,而您不知道它到底在哪里失败,也没有正确回滚。
这也是该标准的一个阴暗角落,我上次检查时在许多主流库实现中实际上并未正确实现。(当我刚刚重新检查时,情况并非如此。);-)
不对可能格式错误的输入使用的其他原因fscanf()包括但不限于根本没有妥善处理数字溢出。
的预期用途fscanf()是扫描已知的格式良好的数据,最好是由同一程序使用fprintf(). 它不太适合解析用户输入。
因此,通常的建议是使用 读取整行输入,然后使用等fgets()解析内存中的行,这可以并且将以明确定义的方式处理类似上述的事情。strtol()strtod()
| 归档时间: |
|
| 查看次数: |
183 次 |
| 最近记录: |