std::stoi转换C风格字符串需确保char[]以'\0'结尾,否则未定义;它跳过前导空白、十进制解析、遇非法字符停止,并抛出std::invalid_argument或std::out_of_range异常,务必用try/catch捕获。

用 std::stoi 转换 C 风格字符串(char[])最安全
直接传入 char[] 给 std::stoi 是可行的,但要注意它接收的是 const char*,所以必须确保数组以 '\0' 结尾,否则行为未定义。它会跳过前导空白,按十进制解析,遇到非法字符就停,且抛出异常(如 std::invalid_argument 或 std::out_of_range)。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 始终用
try/catch包裹,尤其输入不可控时 - 确认数组已 null-terminated:比如
char buf[10] = "123";安全;char buf[10]; strcpy(buf, "123");也安全;但char buf[3] = {'1','2','3'};不安全——没留空间给'\0' - 若只需基础十进制转换,
std::stoi(buf)足够;不需要检查剩余字符是否全为数字时,别自己重写跳过逻辑
char buf[10] = "456";
try {
int n = std::stoi(buf);
} catch (const std::exception& e) {
// 处理转换失败
}用 std::atoi 快但不报错,容易掩盖问题
std::atoi 接收 const char*,行为类似 std::stoi,但失败时不抛异常,而是返回 0。这导致无法区分 “字符串是 "0"” 和 “根本不是数字” 两种情况。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 仅用于可信、格式已知的内部数据(比如配置文件里确定写死的数字)
- 绝不能用于用户输入或网络数据
- 如果非要使用,至少配合
std::strtol的endptr参数做验证,否则等于放弃错误反馈
char buf[] = "789abc"; int n = std::atoi(buf); // 返回 789,但不会告诉你后面还有 "abc"
手动遍历转换适合嵌入式或零依赖场景
当不能用 STL(如裸机、RTOS),或需严格控制行为(比如只接受纯数字、不允许空格、不处理符号),就得手写。核心是逐字符判断 c >= '0' && c ,然后累加:<code>val = val * 10 + (c - '0')。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 必须检查溢出:每次乘 10 和加法前,判断是否超过
INT_MAX/10或等于时个位是否超限 - 显式处理正负号:先跳过空格,再看首字符是否为
'+'或'-',记录符号后从下一个开始算 - 遇到非数字立即返回错误码(比如 -1)或设标志位,别硬转
int manual_atoi(const char* s) {
if (!s) return 0;
while (*s == ' ') s++;
bool neg = false;
if (*s == '-') { neg = true; s++; }
else if (*s == '+') s++;
int res = 0;
while (*s >= '0' && *s <= '9') {
int d = *s++ - '0';
if (res > INT_MAX/10 || (res == INT_MAX/10 && d > 7))
return neg ? INT_MIN : INT_MAX;
res = res * 10 + d;
}
return neg ? -res : res;
}为什么不用 std::stringstream?
虽然能用:std::stringstream ss(buf); ss >> n;,但它启动开销大(构造流对象、设置 locale、缓冲区分配),且失败时需调用 ss.fail() 检查,不如 std::stoi 直观。更关键的是,它默认允许前后有空白和 trailing 字符(比如 " 123xyz " 仍成功读出 123),行为不易预测。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 除非已在用 stream 做批量解析,否则没必要为单次转换引入它
- 若坚持用,务必检查
ss.eof()确保整个字符串都被消费,否则可能漏掉非法后缀 - 避免在性能敏感路径(如循环内)反复构造
std::stringstream
最常被忽略的是 null-termination 和异常边界——很多人测试时用字面量数组没问题,一到动态读取或 strncpy 就崩,因为忘了补 '\0';而异常不捕获会导致程序直接 terminate。这两个点比选哪个函数更重要。


















