std::string::compare可直接比较前缀,返回0表示相等;推荐用索引循环或std::mismatch,但需注意长度截断、迭代器越界及边界处理,手动循环最可控。

用 std::string::compare 逐字符比较最直接
不需要手写循环,std::string 自带的 compare 方法能直接比前缀。它返回 0 表示从位置 0 开始、指定长度的子串完全相等——这正好对应公共前缀判断。
常见错误是传错参数:第三个参数是长度,不是结束下标;如果传入超出任一字符串长度,compare 会自动截断,但逻辑容易混乱。
- 先取两个字符串的最小长度:
size_t n = std::min(s1.size(), s2.size()); - 从长度
n往下试,每次调用s1.compare(0, i, s2, 0, i),返回 0 就说明前i个字符相同 - 为避免线性试探开销,更推荐用索引循环:遍历
0到n-1,一旦s1[i] != s2[i]就停,返回s1.substr(0, i)
用 std::mismatch 一行解决,但要注意迭代器边界
std::mismatch 返回第一个不匹配位置的迭代器对,天然适合找公共前缀起点。但它不会自动处理长度不等的情况——如果一个字符串提前结束,mismatch 会在短串末尾停下,此时需额外判断是否真不匹配,还是只是“一方到头”。
典型误用是直接解引用返回的 pair 第二元素而不检查是否等于 s2.end(),导致越界或逻辑错判。
- 正确写法:
auto [it1, it2] = std::mismatch(s1.begin(), s1.end(), s2.begin(), s2.end()); - 公共前缀长度就是
it1 - s1.begin(),但前提是it1 != s1.end() && it2 != s2.end()同时成立才表示中途失配;否则说明其中一个字符串完全包含在另一个里,前缀就是较短的那个 - 可简写为:
return s1.substr(0, it1 - s1.begin());—— 因为substr对越界长度自动截断,安全
手动循环 + 边界防护是最可控的方式
当需要兼容 C++11 以下、或嵌入式环境无 STL 算法支持时,裸循环反而最稳。关键不是“怎么写”,而是“在哪停”:必须同时检查两个索引是否越界,不能只判 i 就完事。
性能上,现代 CPU 分支预测对这种小循环很友好,且避免了函数调用和迭代器构造开销,实测比 mismatch 略快(尤其短字符串)。
- 初始化
size_t i = 0; - 循环条件写成:
i - 退出后直接返回
s1.substr(0, i),不用再 min/max 或分支判断 - 注意:用
size_t而非int,防止空串时i--导致极大正数
空串、中文、UTF-8 字节序列这些边界情况不能靠直觉
公共前缀定义在字节层面还是字符层面?C++ 标准库所有字符串操作都按 char(即字节)处理。这意味着含 UTF-8 中文的字符串,若直接用上述方法,可能在某个汉字中间截断,产生乱码前缀。
这不是 bug,是设计使然。如果你的场景涉及多语言,必须先做 UTF-8 解码,按 Unicode code point 比较——但这已超出 std::string 能力范围,得引入 ICU 或手动解析。
- 纯 ASCII 场景:前述任一方法都安全
- 含 UTF-8 的场景:
s1[0]可能是 0xC3(UTF-8 多字节首字节),单独截取会破坏编码,结果不可用 - 若不确定输入编码,至少加一句断言:
assert(!s1.empty() && !s2.empty() && (s1[0] & 0x80) == 0);快速拦截非 ASCII 输入
实际用哪一种,取决于你是否要处理非 ASCII、是否在意几纳秒性能、以及项目 C++ 标准版本。多数内部工具脚本用手动循环最省心,第三方库集成则优先选 mismatch。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











