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

C语言仅用stdio.h时scanf读取int类型如何拦截浮点输入

问题根因

scanf的%d格式匹配整数时,只会从当前位置连续读取符合整数规则的字符,遇到第一个非法字符就停止,不会消费非法字符,也不会报错:

  • 第一个参数输入浮点数(例如4.2 5)时,第一个%d读到4就停止,后续字符从.开始,第二个%d无法匹配整数,scanf返回1,能被现有校验拦截。
  • 第二个参数输入浮点数(例如3 6.7)时,第一个%d正常读入3,第二个%d读到6就停止,剩余的.7留在输入缓冲区,此时scanf成功匹配2个整数、返回值为2,直接绕过了返回值校验,本质是没有校验两个整数读完后是否存在非法的后缀内容。
修复方案(仅使用stdio.h)

根据使用场景不同,可选择以下两种实现方式:


方案1:适用于OJ/文件重定向输入场景

支持两个整数跨多行输入,校验逻辑为:两个整数读取成功后,逐字符跳过输入流中后续所有空白字符,如果跳过所有空白后仍能读到非EOF的字符,说明输入包含非法内容,直接判定失败。

#include <stdio.h>

void sum(int a, int b);
void dif(int a, int b);
void prod(int a, int b);
void qut(int a, int b);

int main() {
    int x, z;
    int read_cnt = scanf("%d %d", &x, &z);
    if (read_cnt != 2) {
        printf("n/a\n");
        return 2;
    }
    // 校验后续是否存在非法非空白字符
    int c;
    while ((c = getchar()) != EOF) {
        if (c != ' ' && c != '\t' && c != '\n' && c != '\r' && c != '\f' && c != '\v') {
            printf("n/a\n");
            return 2;
        }
    }
    sum(x, z);
    dif(x, z);
    prod(x, z);
    qut(x, z);
    return 0;
}

void sum(int a, int b) {
    printf("%d ", a + b);
}

void dif(int a, int b) {
    printf("%d ", a - b);
}

void prod(int a, int b) {
    printf("%d ", a * b);
}
 
void qut(int a, int b) {
    // 原逻辑中a为0时0/b为合法运算,仅需拦截除数b为0的场景
    if (b == 0) {
        printf("n/a\n");
    } else {
        printf("%d\n", a / b);
    }
}

注:该方案在交互式终端下运行时,需要用户输入完成后按Ctrl+D(macOS/Linux)或Ctrl+Z(Windows)发送EOF才会执行计算,适合非交互的判定场景。


方案2:适用于交互式命令行场景

要求用户在同一行内输入两个整数,输完按回车即可得到结果,不会阻塞等待后续输入,实现方式为先用fgets读取整行输入,再用sscanf解析内容并校验整行合法性:

#include <stdio.h>

void sum(int a, int b);
void dif(int a, int b);
void prod(int a, int b);
void qut(int a, int b);

int main() {
    int x, z, pos;
    char buf[1024];
    // 读取整行输入
    if (fgets(buf, sizeof(buf), stdin) == NULL) {
        printf("n/a\n");
        return 2;
    }
    // 解析两个整数,同时记录解析完成的位置
    int read_cnt = sscanf(buf, "%d %d %n", &x, &z, &pos);
    if (read_cnt != 2) {
        printf("n/a\n");
        return 2;
    }
    // 校验解析位置之后的所有剩余字符是否都是空白
    while (buf[pos] != '\0') {
        char c = buf[pos];
        if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
            printf("n/a\n");
            return 2;
        }
        pos++;
    }
    sum(x, z);
    dif(x, z);
    prod(x, z);
    qut(x, z);
    return 0;
}

void sum(int a, int b) {
    printf("%d ", a + b);
}

void dif(int a, int b) {
    printf("%d ", a - b);
}

void prod(int a, int b) {
    printf("%d ", a * b);
}
 
void qut(int a, int b) {
    if (b == 0) {
        printf("n/a\n");
    } else {
        printf("%d\n", a / b);
    }
}

该方案可以覆盖所有非法场景:空输入、字符串输入、任意位置的浮点数输入、多余字符输入,且交互体验符合普通命令行程序的使用习惯。

内容的提问来源于stack exchange,提问作者v_util

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:24:33