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

C++中如何实现类似C风格的格式化输入且不使用scanf?

C++实现无scanf依赖的C风格兼容格式化输入方案

核心实现逻辑

  • 逐字符解析输入的格式字符串,识别%d、%f、%lf、%s等scanf常用格式标识符
  • 每匹配到一个格式符,从C++标准输入流std::cin读取对应类型的目标数据
  • 每次读取完成后检查流状态,遇到输入类型不匹配时自动清空错误标志和缓冲区残留内容,避免程序崩溃或后续输入逻辑异常
  • 格式字符串中的普通字符与输入流字符做严格匹配,完全对齐scanf的默认行为

完整实现代码

#include <iostream>
#include <cstdarg>
#include <cctype>
#include <cstring>

// 自定义格式化输入函数,兼容scanf常用格式符,无scanf依赖
int my_scanf(const char* format, ...) {
    va_list args;
    va_start(args, format);
    int matched_count = 0;
    char c;

    while (*format != '\0') {
        // 处理格式串中的空白符:匹配任意数量输入空白符
        if (isspace(static_cast<unsigned char>(*format))) {
            while (std::cin.get(c) && isspace(static_cast<unsigned char>(c)));
            if (std::cin.eof()) break;
            std::cin.putback(c);
            format++;
            continue;
        }

        // 处理普通字符:和输入流直接匹配
        if (*format != '%') {
            std::cin.get(c);
            if (std::cin.eof()) break;
            // 普通字符前自动跳过前导空白
            if (isspace(static_cast<unsigned char>(c))) {
                while (std::cin.get(c) && isspace(static_cast<unsigned char>(c)));
                if (std::cin.eof()) break;
            }
            if (c != *format) {
                std::cin.putback(c);
                break;
            }
            format++;
            continue;
        }

        // 解析格式符
        format++;
        if (*format == '\0') break;

        // 数值、字符串类格式符自动跳过前导空白
        if (*format != 'c') {
            while (std::cin.get(c) && isspace(static_cast<unsigned char>(c)));
            if (std::cin.eof()) break;
            std::cin.putback(c);
        }

        bool read_ok = false;
        if (*format == 'd') {
            int* p = va_arg(args, int*);
            if (std::cin >> *p) {
                read_ok = true;
                matched_count++;
            }
        } else if (*format == 'f') {
            float* p = va_arg(args, float*);
            if (std::cin >> *p) {
                read_ok = true;
                matched_count++;
            }
        } else if (*format == 'l' && *(format + 1) == 'f') {
            double* p = va_arg(args, double*);
            if (std::cin >> *p) {
                read_ok = true;
                matched_count++;
            }
            format++; // 跳过lf的l字符
        } else if (*format == 's') {
            char* p = va_arg(args, char*);
            if (std::cin >> p) {
                read_ok = true;
                matched_count++;
            }
        } else if (*format == 'c') {
            char* p = va_arg(args, char*);
            std::cin.get(c);
            *p = c;
            read_ok = true;
            matched_count++;
        } else {
            // 不支持的格式符直接跳过
            format++;
            continue;
        }

        // 读取失败时重置流状态和缓冲区
        if (!read_ok) {
            std::cin.clear();
            std::cin.ignore(1024, '\n');
            break;
        }
        format++;
    }

    va_end(args);
    return matched_count;
}

使用示例

int main() {
    int int_val;
    double double_val;
    char str_buf[256];

    std::cout << "请依次输入整数、浮点数、字符串,以空格分隔:";
    int read_cnt = my_scanf("%d %lf %s", &int_val, &double_val, str_buf);

    std::cout << "成功读取参数个数:" << read_cnt << std::endl;
    if (read_cnt >= 1) std::cout << "读取到的整数:" << int_val << std::endl;
    if (read_cnt >= 2) std::cout << "读取到的浮点数:" << double_val << std::endl;
    if (read_cnt >= 3) std::cout << "读取到的字符串:" << str_buf << std::endl;

    return 0;
}

扩展说明

  • 当前实现已覆盖最常用的格式符,需要支持十六进制%x、无符号整数%u等其他格式符时,只需在格式符判断分支中新增对应类型的读取逻辑即可
  • 字符串读取默认无长度限制,生产环境使用时可增加长度参数传入,避免缓冲区溢出风险
  • 输入类型不匹配时默认清空当前行剩余内容,可根据需求调整ignore的参数修改错误处理逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 05:54:00