3 回答
TA贡献1775条经验 获得超11个赞
根据C语言标准(n1256):
7.19.6.2 fscanf函数
...
4 fscanf函数依次执行格式的每个指令。如果指令失败,如下所述,函数将返回。失败描述为输入失败(由于发生编码错误或输入字符不可用)或匹配失败(由于不适当的输入)。
...
7作为转换规范的指令定义了一组匹配的输入序列,如下文针对每个说明符所述。转换说明将按照以下步骤执行:
8除非输入规范中包含[,c或n说明符,否则将跳过输入的空白字符(由isspace函数指定)。250)
9从流中读取一个输入项,除非规范包括n个说明符。输入项定义为最长的输入字符序列,该序列不超过任何指定的字段宽度,并且是匹配输入序列的前缀,或者是匹配输入序列的前缀。251)输入项之后的第一个字符(如果有)保持未读状态。如果输入项的长度为零,则该指令的执行失败;否则,该指令的执行失败。除非文件末尾,编码错误或读取错误阻止了来自流的输入,否则此条件是匹配失败,在这种情况下,这是输入失败。
10除非是%说明符,否则输入项(或者,如果是%n指令,即输入字符数)转换为适合转换说明符的类型。如果输入项不是匹配序列,则指令的执行失败:此条件是匹配失败。除非用*表示禁止分配,否则转换结果将放置在尚未收到转换结果的format参数后面的第一个参数指向的对象中。如果该对象没有适当的类型,或者无法在对象中表示转换结果,则该行为是不确定的。
在第10段中添加了重点。%d转换说明符希望输入文本的格式设置为十进制整数。如果不是,则转换失败,并且导致转换失败的字符保留在输入流中。scanf()使用%d转换说明符进一步调用将会阻塞相同的字符。
scanf()返回成功分配的数量;您需要检查此结果以查看转换是否成功,如下所示:
int x = 0;
while (x != 4)
{
int result = scanf("%d", &x);
if (result != 1)
{
printf("Last call to scanf() failed; exiting\n");
break;
}
}
不幸的是,您仍然将错误的输入卡在输入流中。有许多策略可以解决这个问题。您可以使用删除令人反感的字符,getchar然后重试:
while (x != 4)
{
int tmp;
if (scanf("%d", &tmp) == 0)
getchar();
else
x = tmp;
}
或者,您可以尝试读取下一个换行符,假设所有剩余的输入都为b0rked:
while (x != 4)
{
int tmp;
if (scanf("%d", &tmp) == 0)
while (getchar() != '\n')
;
else
x = tmp;
}
或者,您可以尝试将输入读取为文本,然后使用strtol()(我的首选技术)将其转换为整数:
char input[SOME_SIZE];
int x = 0;
...
while (x != 4)
{
if (fgets(input, sizeof input, stdin))
{
char *check;
int tmp = (int) strtol(input, &check, 10);
if (!isspace(*check) && *check != 0)
{
printf("%s is not a valid integer: try again\n", input);
}
else
{
x = tmp;
}
}
else
{
printf("Read error on standard input\n");
break;
}
}
这需要做更多的工作,但可以让您在将错误的输入分配给之前捕获错误的输入x。
TA贡献1860条经验 获得超8个赞
您无需检查scanf
实际是否成功,因此会陷入错误。对于每个循环,scanf
都会尝试读取并失败。
scanf
返回成功读取项的数量,因此将循环修改为如下形式 while (x!=4) { if (scanf("%d",&x) != 1) break; }
TA贡献1804条经验 获得超2个赞
当scanf在输入流中的特定位置停止扫描时,它将永远不会推进该流,因此下一个scanf将再次尝试相同的错误...并再次尝试...
输入:42 23 foo ...
scanf:^
x 42
scanf:^
x 23
scanf:^
x无法使用
scanf:^
x无法使用
scanf:^
x无法使用
scanf:^
x无法使用
scanf:^
x无法使用
- 3 回答
- 0 关注
- 863 浏览
添加回答
举报