substr是std::string成员函数,有两个重载:无参版取0到末尾,二参版substr(pos,len)中pos为起始下标、len为字符数(非结束下标);pos越界抛out_of_range异常,pos等于长度时返回空串,len超长则自动截断。

substr 函数的基本用法和参数含义
substr 是 std::string 的成员函数,不是全局库函数,调用前必须确保对象是 std::string 类型。它有两个重载形式:substr()(无参,默认取从 0 到末尾)和 substr(size_t pos, size_t len)(常用)。第一个参数 pos 是起始下标(从 0 开始),第二个参数 len 是要截取的字符个数,**不是结束下标**。
常见错误:传入 pos 超出字符串长度(比如 s.substr(10, 3) 但 s.length() == 5),此时会抛出 std::out_of_range 异常。C++11 起不接受负数索引,也不支持 Python 风格的倒序写法(如 -2)。
- 若
pos == str.length(),返回空字符串""(合法) - 若
len超出剩余长度,substr自动截断到末尾,不会报错 - 避免裸写
s.substr(i, j-i)而不检查i 和i
替代方案:用迭代器 + string 构造更灵活地截取
当需要基于位置计算复杂、或想复用已有迭代器时,直接构造 std::string 比 substr 更安全。例如从第 2 个字符开始取 4 个:
std::string s = "hello world"; std::string sub(s.begin() + 2, s.begin() + 6); // "llo "
这种方式绕过了 substr 对 pos 范围的严格检查,但要求两个迭代器都在合法范围内(否则行为未定义)。适用于已知有效区间、或配合 find/find_first_of 等返回迭代器的算法使用。
立即学习“C++免费学习笔记(深入)”;
- 比
substr少一次边界检查开销(但通常可忽略) - 不能用于
std::string_view直接构造(需先转为std::string或用其 ownsubstr) - 注意:
s.begin() + n对短字符串高效,对std::list<:string>这类不支持随机访问的容器不适用
处理中文或 UTF-8 字符串时 substr 会出问题吗
会。substr 按字节操作,不识别 UTF-8 编码单元。例如一个汉字通常占 3 字节,若在中间截断,结果是非法 UTF-8 字节序列,后续输出或转换可能乱码或失败。
没有标准库内置的 UTF-8 安全子串函数。实际项目中应:
- 优先用
std::string_view+ 第三方库(如 ICU、utf8cpp)做 Unicode-aware 截取 - 若确定输入只含 ASCII,
substr安全可用 - 避免用
substr做“取前 N 个字符”逻辑,改用循环 +utf8::next类函数计数码点
std::string_view::substr 性能优势与使用限制
C++17 引入的 std::string_view 也有 substr 成员函数,它不分配内存,只记录起始指针和长度,因此零拷贝、极快。但它要求原始字符串生命周期长于 string_view 对象本身。
const char* raw = "temp data";
std::string_view sv(raw);
auto part = sv.substr(2, 4); // 安全:raw 仍有效
// 但下面这行危险:
// auto bad = std::string("hello").substr(1, 3); // 错!临时 string 析构后 view 悬空-
string_view::substr参数语义和string::substr完全一致 - 不能隐式转成
std::string,需要显式调用std::string(view)构造 - 在函数参数中优先用
string_view接收,内部再按需调用substr,避免无谓拷贝
C++ 的 substr 看似简单,真正容易出错的是边界条件、UTF-8 处理和生命周期管理——尤其混用 string_view 时,悬空指针比越界访问更难调试。










