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
相关产品推荐
相关产品推荐

