在C++标准库中,std::string的substr函数是实现字符串截取的核心接口,它的使用场景非常广泛,比如提取文件路径中的文件名、解析协议头中的字段等。不过很多开发者在使用时容易忽略参数边界问题,导致程序运行时出现未定义行为。

substr函数基本用法
substr是std::string类的成员函数,原型如下:
// 函数原型 std::string substr(size_t pos = 0, size_t count = npos) const;
它的两个参数含义分别是:
- pos:截取的起始位置,从0开始计数,必须是有效位置或者等于字符串的长度
- count:需要截取的字符数量,默认值是
std::string::npos,表示截取到字符串末尾
下面是一个基础的使用示例:
#include <iostream>
#include <string>
int main() {
std::string str = "hello world";
// 从位置2开始截取3个字符
std::string sub1 = str.substr(2, 3);
// 从位置6开始截取到末尾
std::string sub2 = str.substr(6);
std::cout << "sub1: " << sub1 << std::endl; // 输出 llo
std::cout << "sub2: " << sub2 << std::endl; // 输出 world
return 0;
}
参数越界的触发场景
substr的参数越界主要分两种情况,只要满足其中一种就会触发未定义行为:
1. 起始位置pos超过字符串长度
当pos的值大于当前字符串的长度时,就会触发越界。比如字符串长度是5,传入的pos是6,此时就会报错。
#include <iostream>
#include <string>
int main() {
std::string str = "test"; // 长度为4,有效pos范围是0-4
// pos=5超过字符串长度,触发越界
std::string sub = str.substr(5, 2);
return 0;
}
2. 截取长度count超出剩余字符数
当pos是有效位置,但pos + count超过了字符串的长度,且count不是std::string::npos时,也会触发越界。比如字符串长度是4,pos是2,count是3,此时剩余字符只有2个,截取的字符数超出剩余量就会越界。
#include <iostream>
#include <string>
int main() {
std::string str = "test"; // 长度为4
// pos=2,剩余字符是2个,count=3超出剩余量,触发越界
std::string sub = str.substr(2, 3);
return 0;
}
不同编译器的越界表现
参数越界属于C++标准中的未定义行为,不同编译器的处理方式会有差异:
- 在GCC编译器下,通常会直接抛出
std::out_of_range异常,程序终止运行 - 在MSVC编译器下,调试模式会触发断言失败,弹出错误提示; release模式可能不会报错,但会返回不可预期的结果
- 部分老旧编译器可能不会做任何检查,直接返回错误的字符串内容,导致后续逻辑出错
避免参数越界的处理方案
为了避免substr参数越界,我们可以在使用前做参数校验,调整参数到合法范围:
方案一:手动校验参数
先判断pos是否超过字符串长度,再计算实际可截取的长度,避免传入非法参数。
#include <iostream>
#include <string>
#include <algorithm>
std::string safe_substr(const std::string& str, size_t pos, size_t count = std::string::npos) {
// 如果起始位置超过字符串长度,返回空字符串
if (pos >= str.size()) {
return "";
}
// 如果count是npos或者pos+count超过字符串长度,调整count为剩余字符数
if (count == std::string::npos || pos + count > str.size()) {
count = str.size() - pos;
}
return str.substr(pos, count);
}
int main() {
std::string str = "hello";
// 正常截取
std::cout << safe_substr(str, 1, 3) << std::endl; // 输出 ello
// 起始位置越界,返回空
std::cout << safe_substr(str, 10, 2) << std::endl; // 输出 空
// 截取长度超出剩余量,自动调整到末尾
std::cout << safe_substr(str, 3, 5) << std::endl; // 输出 lo
return 0;
}
方案二:捕获异常
如果确定编译器会在越界时抛出异常,也可以使用try-catch块捕获std::out_of_range异常来处理错误。
#include <iostream>
#include <string>
int main() {
std::string str = "hello";
try {
std::string sub = str.substr(6, 2);
std::cout << sub << std::endl;
} catch (const std::out_of_range& e) {
std::cout << "截取字符串参数越界: " << e.what() << std::endl;
}
return 0;
}
注意事项
需要注意pos等于字符串长度是合法的情况,此时无论count是多少,都会返回空字符串,不会触发越界。比如str.substr(str.size(), 5)的返回结果是空字符串,这是符合标准的正常行为。
在实际开发中,建议优先使用参数校验的方案,因为未定义行为的不确定性会带来隐藏的bug,提前校验参数可以让代码更健壮。
C++_substr字符串截取参数越界异常处理修改时间:2026-07-22 05:57:30