C语言中仅使用scanf处理0-100范围整数输入的非法输入规避问题求解
解决scanf输入非整数导致的程序异常问题
我明白你遇到的麻烦了——用scanf("%d")读取ID时,用户输入字母这类非数字内容,要么程序崩溃,要么错误识别成0,而且你还想确保输入是0-100之间的整数、没有重复ID。之前尝试过getch但不知道怎么处理多位数,下面给你几个靠谱的解决方案:
方案一:修复scanf的使用逻辑
scanf的返回值其实能帮我们判断是否成功读取到整数——它会返回成功匹配的输入项数量。如果用户输入的不是整数,scanf返回0,这时候我们需要清空输入缓冲区里的垃圾数据,避免下次循环重复读取错误内容。
修改后的代码如下:
do { printf("Enter ID: "); // 重置id为无效值,避免上次错误残留 NewWorkder->id = -1; // 检查scanf是否成功读取整数 int scan_result = scanf("%d", &NewWorkder->id); // 如果读取失败(输入非整数) if (scan_result != 1) { // 清空输入缓冲区的所有字符,直到换行或EOF int c; while ((c = getchar()) != '\n' && c != EOF); printf("Invalid input! Please enter an integer.\n"); continue; } // 检查ID范围和是否重复 TargetList = FillWorker(); TargetList = SeekList(Head, NewWorkder->id); } while (NewWorkder->id < 0 || NewWorkder->id > 100 || TargetList != NULL); // 后续写入文件等逻辑保持不变 fprintf(filemechanic,"%s %s %d\n", NewWorker->name, NewWorker->surname, NewWorker->id); free(TargetList); fclose(filemechanic);
关键说明:
- 每次循环先重置
id为-1,避免上次错误输入导致的残留值干扰判断 - 通过
scanf的返回值判断是否成功读取整数,失败则清空缓冲区 - 清空缓冲区用
getchar()循环,把所有未处理的字符(包括换行)都读掉,保证下次输入不受影响
方案二:用fgets+strtol读取整行输入(更安全)
如果想彻底避免scanf的缓冲区问题,推荐先通过fgets读取整行输入,再用strtol转换为整数——这种方法能完全控制输入内容,避免异常。
代码示例:
#include <stdlib.h> #include <string.h> #include <ctype.h> do { printf("Enter ID: "); char input_buf[256]; // 读取整行输入 if (fgets(input_buf, sizeof(input_buf), stdin) == NULL) { // 处理输入错误(比如EOF) printf("Input error!\n"); exit(1); } // 去掉换行符(如果存在) input_buf[strcspn(input_buf, "\n")] = '\0'; // 检查输入是否为空 if (strlen(input_buf) == 0) { printf("Please enter a valid ID!\n"); continue; } // 检查输入是否全为数字(可选,提前过滤非数字) for (int i=0; input_buf[i]!='\0'; i++) { if (!isdigit(input_buf[i])) { printf("Invalid input! Please enter an integer.\n"); NewWorkder->id = -1; goto check_loop; } } // 转换为整数 char *endptr; long id_num = strtol(input_buf, &endptr, 10); // 检查转换是否成功,且没有多余字符 if (endptr == input_buf || *endptr != '\0') { printf("Invalid input! Please enter an integer.\n"); NewWorkder->id = -1; goto check_loop; } // 转换为int并赋值 NewWorkder->id = (int)id_num; check_loop: // 检查ID范围和是否重复 TargetList = FillWorker(); TargetList = SeekList(Head, NewWorkder->id); } while (NewWorkder->id < 0 || NewWorkder->id > 100 || TargetList != NULL); // 后续逻辑不变 fprintf(filemechanic,"%s %s %d\n", NewWorker->name, NewWorker->surname, NewWorker->id); free(TargetList); fclose(filemechanic);
关键说明:
fgets读取整行,避免scanf的缓冲区残留问题strtol转换时可以通过endptr检查是否所有字符都成功转换为数字- 提前用
isdigit遍历输入,能快速过滤包含非数字的输入
关于getch处理多位数的补充
如果你还是想用getch,可以手动拼接数字:
#include <conio.h> // 注意:getch是非标准函数,不同平台可能有差异 int get_valid_id() { int num = 0; char c; printf("Enter ID: "); while ((c = getch()) != '\r') { // 回车结束输入 if (isdigit(c)) { num = num * 10 + (c - '0'); putchar(c); // 回显输入的字符 } else if (c == '\b' && num > 0) { // 处理退格 num /= 10; printf("\b \b"); // 清除回显的字符 } } printf("\n"); return num; }
不过这种方法需要处理退格、输入范围限制等细节,而且getch是平台相关的(比如Linux下用getch需要链接ncurses库),所以更推荐前面两种标准方法。
内容的提问来源于stack exchange,提问作者LuQchor
相关产品推荐
相关产品推荐

