17370845950

C++ 怎么截取子串 C++ substr函数参数说明与越界处理【操作】
substr的pos为起始索引(0起),len为截取长度而非结束位置;pos>size()抛异常,pos==size()返回空串,len超限则自动截断至末尾。

substr 的两个参数到底怎么填

substrstd::string 的成员函数,签名是 string substr(size_t pos = 0, size_t len = npos) const。第一个参数 pos 是起始位置(从 0 开始),第二个参数 len 是要截取的字符个数(不是结束位置)。

常见误用是把 len 当成“到第几个字符为止”,比如想取索引 2 到 5(共 4 个字符),写成 s.substr(2, 5) —— 这会取 5 个字符,越界风险陡增。

  • pos 超出字符串长度(pos > size())会抛 std::out_of_range
  • pos == size() 是合法的,返回空串;pos == size() + 1 就越界了
  • len 超过剩余字符数时,substr 自动截断到末尾,不会报错(这是安全设计)

越界时怎么避免程序崩溃

不能

依赖“运气”——哪怕你认为 pos 不会超,运行时输入不可控,必须主动防御。

  • 检查 pos:用 if (pos ,注意是 (因为 pos == s.size() 合法)
  • 不推荐裸调 try/catch 捕获 std::out_of_range,开销大且掩盖逻辑问题
  • 更稳妥的做法是先算安全范围:size_t safe_pos = std::min(pos, s.size());,再传入 substr
  • 如果业务上 pos 来自用户输入或外部解析,建议封装一层带校验的工具函数

和 C 风格字符串、std::string_view 的行为差异

substr 返回的是新分配的 std::string,有拷贝开销;而 std::string_viewsubstr 只是视图切片,零拷贝但依赖原字符串生命周期。

  • C 风格(strncpy 等)需手动管理内存和终止符,容易缓冲区溢出,不推荐在 C++ 中用于子串提取
  • std::string_view::substr 同样接受 poslen,但越界时行为是未定义(UB),不是抛异常 —— 必须确保调用前已校验
  • 若只读且性能敏感(如解析日志、协议字段),优先用 string_view::substr 并配合 assert 或预检

一个防越界的实用封装示例

直接用原生 substr 容易漏判,下面这个小函数把边界逻辑收拢了:

std::string safe_substr(const std::string& s, size_t pos, size_t len = std::string::npos) {
    if (pos >= s.size()) return "";
    len = std::min(len, s.size() - pos);
    return s.substr(pos, len);
}

它处理了三种典型越界场景:pos 超长、len 过大、两者叠加。注意返回空串而不是抛异常——是否该报错,取决于你的业务语义,这里默认“取不到就为空”。

真正容易被忽略的是:当 pos 来自另一个子串的查找结果(比如 s.find("key") + offset),必须确认 find 返回的不是 npos,否则 npos + offset 会整数回绕成极大值,直接触发越界。这个坑比参数记错更隐蔽。