You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 17:29:06