字符串转数字时,可能会遇到哪些问题?

结合 C++ 常用的C++11 系列函数(stoi/stod 等)C 风格函数(atoi/atof 等),梳理字符串转数字的常见问题、现象、原因及规避方案。

一、整体分类

主要分为:格式非法数值溢出截断解析空/空白字符串符号与进制问题浮点数特殊场景


二、逐个问题详解 + 示例

1. 字符串含非数字字符(最常见)

场景1:开头就是非法字符

字符串首字符不是数字、正负号,无法解析。

  • atoi/atof:直接返回 0,无任何报错,难以察觉。
  • stoi/stod:直接抛出 invalid_argument 异常,程序崩溃。
cpp 复制代码
string s = "abc123";
int a = atoi(s.c_str());   // 结果:0
int b = stoi(s);           // 抛异常

场景2:中间/末尾夹杂非数字

函数会从左到右解析,遇到非法字符立即停止,只取前面合法部分。

cpp 复制代码
string s = "123xyz456";
int a = atoi(s.c_str()); // 结果:123
int b = stoi(s);         // 结果:123(不会报错,只截断)

2. 数值超出目标类型范围(溢出)

字符串表示的数字太大/太小,超过接收变量的取值范围。

① C 风格 atoi/atol/atof

无报错、无提示 ,直接产生未定义行为,结果乱码、负数、随机值。

cpp 复制代码
// int 范围:-2147483648 ~ 2147483647
string s = "999999999999"; 
int num = atoi(s.c_str()); 
// 溢出,结果不可预测

② C++11 stoi/stoll/stod

溢出会抛出 out_of_range 异常,程序直接终止。

cpp 复制代码
string s = "999999999999";
int num = stoi(s); // 数值超出 int 范围,抛异常

3. 空字符串 / 全空白字符串

  • 空串 ""、全空格 " "、制表符 "\t"、换行 "\n"
  • atoi:返回 0
  • stoi:抛出 invalid_argument 异常
cpp 复制代码
string s = "";
atoi(s.c_str());  // 0
stoi(s);          // 异常

4. 正负号使用异常

  1. 多个正负号 :如 "+-123""--456"
    • atoi 返回 0
    • stoi 抛参数异常
  2. 符号不在开头"123-45"
    解析到 123 就截断,后面忽略。
cpp 复制代码
string s = "-+123";
atoi(s.c_str()); // 0
stoi(s);         // 异常

5. 浮点数专属问题

(1)整型函数解析小数字符串

stoi/atoi 解析带小数点的字符串:

  • 自动截断小数部分,只保留整数:
cpp 复制代码
string s = "3.99";
int a = atoi(s.c_str()); // 3
int b = stoi(s);         // 3

(2)科学计数法

1e32.5E-2 这类科学计数:

  • atof / stod 支持正常转换
  • atoi / stoi 识别到 e/E 停止,只解析前面数字

(3)无穷、非数值(NaN)

字符串 "inf" "nan":浮点函数可识别,整型函数判定为非法。


6. 进制不匹配问题

函数默认只解析十进制

  • 八进制 0123、十六进制 0x1A
    atoi/stoi 不会按进制解析,只会当成普通十进制:
    • "0123" → 123
    • "0x1A" → 0(x 是非法字符)

如果需要解析十六进制/八进制,不能用普通转换函数。


7. 前导空格问题

字符串开头有空格

两类函数都能自动忽略前导空白,正常解析:

cpp 复制代码
string s = "  678";
atoi(s.c_str()); // 678
stoi(s);         // 678

⚠️ 仅开头空格允许,中间/末尾空格仍属于截断。


三、两类函数问题对比表

问题场景 atoi/atof(C风格) stoi/stod(C++11)
非法开头字符 返回 0,无告警 invalid_argument 异常
数值溢出 未定义行为,结果错乱 out_of_range 异常
空串/全空白 返回 0 抛异常
中间含非数字 截断前面合法部分 截断前面合法部分
前导空格 自动忽略,正常解析 自动忽略,正常解析

四、通用规避方案(实用写法)

1. 使用 C++11 系列函数:必须捕获异常

cpp 复制代码
#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;

bool strToInt(const string& s, int& outNum)
{
    try
    {
        outNum = stoi(s);
        return true;
    }
    catch (const invalid_argument&)
    {
        cout << "参数非法" << endl;
    }
    catch (const out_of_range&)
    {
        cout << "数值溢出" << endl;
    }
    return false;
}

2. 使用 C 风格函数:提前做格式校验

手动遍历字符串,判断是否为合法数字、检查范围,避免得到误导性的 0

3. 通用稳健方案:stringstream

流转换会通过状态位判断转换是否成功,不抛异常、不静默出错:

cpp 复制代码
#include <sstream>
bool strToInt(const string& s, int& num)
{
    stringstream ss(s);
    ss >> num;
    // 判断转换是否成功 + 字符串是否全部解析完毕
    return ss.good() && ss.eof();
}

优点:能精准区分「转换失败」和「正常转成 0」,工业代码常用。


五、总结高频考点

  1. C 风格函数最大坑:出错只返回 0,无法区分是真 0 还是转换失败;溢出无提示。
  2. C++11 stoi 系列最大坑:非法格式、溢出直接抛异常,不捕获就崩程序。
  3. 中间含字母/符号:两类函数都会截断解析
  4. 空串、多正负号:属于典型非法格式。
  5. 追求健壮性优先用 stringstream + 状态位判断
相关推荐
许彰午1 小时前
责任链模式实战——同一个框架里的两种链
java·开发语言·责任链模式
寻道码路1 小时前
LangChain4j Java AI 应用开发实战(十四):手写 RAG 全流程 - 深入理解每个环节
java·开发语言·人工智能·ai
云烟成雨TD2 小时前
Agent Scope Java 2.x 系列【1】核心架构
java·人工智能·agent
rit84324992 小时前
MATLAB近红外光谱预处理:平滑与求导(MSV方法)
数据结构·算法·matlab
愛~杦辷个訾2 小时前
Java Springboot使用阿里云oss对图片进行等质量压缩,转换成webp格式的压缩图。
java·spring boot·阿里云·oss
吴阿福|一人公司2 小时前
Python 类变量修改的压力测试:高并发场景
开发语言·python
蚂蚁数据AntData2 小时前
从ChatBI到业务记忆:重新定义数据智能的生产力边界
大数据·网络·数据库·人工智能·算法
_日拱一卒2 小时前
LeetCode:22括号生成
算法·leetcode·职场和发展
cfm_29142 小时前
JVM垃圾收集算法与收集器深度解析
jvm·测试工具·算法·性能优化