1、问题说明
C 中,scanf
用于从用户读取输入。然而,它有一些奇怪的行为,可能会导致某些输入读取时出现问题。特别是,如果输入与预期格式不匹配,scanf
可能会失败,但它不会清空输入缓冲区。这会导致如果程序一直尝试读取相同的无效输入,就进入无限循环。
#include <stdio.h> int main() { int x; while (1) { printf("Enter a number: "); scanf("%d", &x); // 读取一个整数 if (x != 0) { break; // 如果输入的是非零数字,跳出循环 } printf("Invalid input! Please try again.\n"); } return 0; }
2、发生无限循环的原因
如果用户输入了与预期格式不匹配的内容(例如,在预期输入整数时输入了字符串),scanf
将无法正确读取输入。在这种情况下,scanf
会失败,并且不会清空输入缓冲区。
当 scanf
遇到无效输入时,它不会自动清空缓冲区。无效的输入仍然存在,当循环再次迭代时,scanf
会读取相同的无效输入,导致失败,再次进入循环。
输入非数字字符给 %d
, 如果用户在期望整数的地方输入了非数字字符(例如 abc
),scanf
无法将其解析为整数,并且会将无效字符留在输入缓冲区。
格式说明符不匹配,
如果使用错误的格式说明符,例如预期输入整数但实际输入浮动数,也会导致 scanf
失败,并且缓冲区中的内容不会被消费。
3、解决方法
1)清空输入缓冲区
当 scanf
读取失败时,可以通过读取并丢弃无效输入来清空输入缓冲区。常见的方法是使用 getchar()
来消费缓冲区中的字符。
#include <stdio.h> int main() { int x; while (1) { printf("Enter a number: "); if (scanf("%d", &x) != 1) { // 清空输入缓冲区 while (getchar() != '\n'); // 丢弃无效输入 printf("Invalid input! Please try again.\n"); } else { if (x != 0) { break; // 如果输入的是非零数字,跳出循环 } } } return 0; }
2)使用 fgets()
来处理输入
另一种方法是使用 fgets()
读取整个输入行作为字符串,然后使用 sscanf()
解析该字符串为所需的格式。
#include <stdio.h> #include <stdlib.h> int main() { int x; char buffer[100]; while (1) { printf("Enter a number: "); if (fgets(buffer, sizeof(buffer), stdin)) { if (sscanf(buffer, "%d", &x) == 1) { if (x != 0) { break; // 如果输入的是非零数字,跳出循环 } } } printf("Invalid input! Please try again.\n"); } return 0; }