输入不匹配的字符串时,Scanf 无法在 while 循环中工作
Scanf not working in while loop when nonmatching string is entered
我正在使用一个名为 checkType 的函数来检查用户是否输入了有效的整数类型输入。例如,如果用户输入 15,它将打印 valid,而 15c 将打印 not valid。但是,如果用户只输入像ccccc这样的字符串输入,就会导致死循环,程序崩溃。我在下面添加了一些屏幕截图来显示输出。
int checkType(int input, char *c) {
if (input == 2 and *c == '\n') {
return 1;
} else {
return 0;
};
}
int main(void) {
int faces = 0;
char c;
int valid = 0;
int input;
while (valid == 0) {
printf("Enter number of faces: ");
input = scanf("%d%c", &faces, &c);
valid = checkType(input, &c);
printf(valid == 0 ? "not valid\n" : "valid\n");
}
}
无限循环:
scanf()
函数族并不是真正为输入有问题的语法而设计的。
解决问题的常用方法是以一定会成功的方式读入所有输入,例如通过使用 fgets()
读取完整的一行(而不是数字、类似单词的字符串或任何其他具有预期格式的内容)。
然后您可以尝试按照预期格式解析该行表示字符串。 (您可以使用 sscanf()
进行解析尝试。)如果失败,您将忽略它并阅读下一行,或者尝试根据相同输入的替代允许格式进行解析。
相关区别在于读取整行会成功并将其从输入流中移除。与此相反,如果出现语法错误,您的代码会在输入流中留下任何与预期语法不匹配的内容。因此,它当然会再次失败读取循环的下一次迭代。这就是导致无限循环的原因。
详细:
- 将整行读入缓冲区,
使用 fgets()
和将字符数限制为缓冲区大小的选项
- 此时所有行都从输入中删除(又名标准输入,又名输入流),
这意味着即使读取的行不匹配任何允许的格式,下一次读取也会获得新的输入,
这是与尝试使用 scanf()
直接读取输入的相关区别
- 从行缓冲区中,尝试根据允许的格式读取单独的值,
使用 sscanf()
并检查 return 值
- 如果成功很好,你已经填充了预期的变量(例如整数);
您可以尝试扫描额外的、未覆盖格式的尾随输入(并继续检查不正确的输入,即使行的开头匹配允许的格式)
- 如果不成功,请尝试不同的允许格式,
再次使用 sscanf()
,
来自同一行缓冲区,即使格式部分匹配也不会更改
- 如果没有允许的格式与输入相匹配,则认为它不正确
- 不正确的输入可以被忽略或者会在你的程序中导致致命的解析错误,你的选择
However, if the user enters a string input only like ccccc,
it results in an infinite loop and the program crashes
原因:scanf
returns 来自 stdin
的有效读取值的数量。如果我们给 cccc
作为输入, scanf
无法读取值,因为输入和变量 faces
是不同的数据类型。这使得 input = 0
。所以函数 checkType
returns 0,这反过来使得 valid = 0
。这使得 while(valid == 0)
始终为真,因此无限循环。
Scanf 将从标准输入中读取,如果不匹配则不清除标准输入缓冲区。所以在你的情况下它会再次读取错误的数据,你可以在 scanf 之后添加一个带有 stdin 的干净函数,比如:__fpurge(stdin)
您可以参考以下两个链接:
对于 "ccccc"
和 scanf("%d%c" ...
这样的输入,不会转换为 int
。 scanf()
returns 0 和stdin
保持不变。再次调用该函数结果相同。
代码需要以某种方式消耗错误的输入。
研究 fgets()
以阅读 行 用户输入。
我正在使用一个名为 checkType 的函数来检查用户是否输入了有效的整数类型输入。例如,如果用户输入 15,它将打印 valid,而 15c 将打印 not valid。但是,如果用户只输入像ccccc这样的字符串输入,就会导致死循环,程序崩溃。我在下面添加了一些屏幕截图来显示输出。
int checkType(int input, char *c) {
if (input == 2 and *c == '\n') {
return 1;
} else {
return 0;
};
}
int main(void) {
int faces = 0;
char c;
int valid = 0;
int input;
while (valid == 0) {
printf("Enter number of faces: ");
input = scanf("%d%c", &faces, &c);
valid = checkType(input, &c);
printf(valid == 0 ? "not valid\n" : "valid\n");
}
}
无限循环:
scanf()
函数族并不是真正为输入有问题的语法而设计的。
解决问题的常用方法是以一定会成功的方式读入所有输入,例如通过使用 fgets()
读取完整的一行(而不是数字、类似单词的字符串或任何其他具有预期格式的内容)。
然后您可以尝试按照预期格式解析该行表示字符串。 (您可以使用 sscanf()
进行解析尝试。)如果失败,您将忽略它并阅读下一行,或者尝试根据相同输入的替代允许格式进行解析。
相关区别在于读取整行会成功并将其从输入流中移除。与此相反,如果出现语法错误,您的代码会在输入流中留下任何与预期语法不匹配的内容。因此,它当然会再次失败读取循环的下一次迭代。这就是导致无限循环的原因。
详细:
- 将整行读入缓冲区,
使用fgets()
和将字符数限制为缓冲区大小的选项 - 此时所有行都从输入中删除(又名标准输入,又名输入流),
这意味着即使读取的行不匹配任何允许的格式,下一次读取也会获得新的输入,
这是与尝试使用scanf()
直接读取输入的相关区别
- 从行缓冲区中,尝试根据允许的格式读取单独的值,
使用sscanf()
并检查 return 值 - 如果成功很好,你已经填充了预期的变量(例如整数);
您可以尝试扫描额外的、未覆盖格式的尾随输入(并继续检查不正确的输入,即使行的开头匹配允许的格式) - 如果不成功,请尝试不同的允许格式,
再次使用sscanf()
,
来自同一行缓冲区,即使格式部分匹配也不会更改 - 如果没有允许的格式与输入相匹配,则认为它不正确
- 不正确的输入可以被忽略或者会在你的程序中导致致命的解析错误,你的选择
However, if the user enters a string input only like ccccc,
it results in an infinite loop and the program crashes
原因:scanf
returns 来自 stdin
的有效读取值的数量。如果我们给 cccc
作为输入, scanf
无法读取值,因为输入和变量 faces
是不同的数据类型。这使得 input = 0
。所以函数 checkType
returns 0,这反过来使得 valid = 0
。这使得 while(valid == 0)
始终为真,因此无限循环。
Scanf 将从标准输入中读取,如果不匹配则不清除标准输入缓冲区。所以在你的情况下它会再次读取错误的数据,你可以在 scanf 之后添加一个带有 stdin 的干净函数,比如:__fpurge(stdin)
您可以参考以下两个链接:
对于 "ccccc"
和 scanf("%d%c" ...
这样的输入,不会转换为 int
。 scanf()
returns 0 和stdin
保持不变。再次调用该函数结果相同。
代码需要以某种方式消耗错误的输入。
研究 fgets()
以阅读 行 用户输入。