最直接的方式是使用 std::reverse,它位于 <algorithm> 头文件中,作用于支持随机访问迭代器的容器(如 std::string),需传入 begin() 和 end() 迭代器,不可对 c_str() 调用;含嵌入空字符时仍正常,但 UTF-8 字符串需注意字节序破坏风险。

用 std::reverse 是最直接的方式
标准库提供了现成的、高效且安全的方案,不需要手写循环。它在 <algorithm> 头文件里,作用于任意支持随机访问迭代器的容器,包括 std::string。
常见错误是传错迭代器范围,比如漏掉 .end() 或误用 .c_str()——后者返回只读 C 风格字符串,不能被修改。
- 正确写法:
#include <algorithm> #include <string> <p>std::string s = "hello"; std::reverse(s.begin(), s.end()); // ✅ 修改原字符串
- 别对
s.c_str()调用std::reverse,它返回const char*,编译不过 - 如果字符串含嵌入空字符(
\0),std::string仍能正常反转,因为它按size()而非 C 风格终止符处理
手动遍历交换要注意边界条件
适合理解原理或受限于环境(如裸机、禁用 STL),但容易在索引计算上出错,尤其当字符串长度为 0 或 1 时。
关键点在于只遍历前半段,避免重复交换甚至越界。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 循环上限必须是
s.length() / 2,不是s.length() - 用
size_t做索引时,注意i 在空串下不会进循环(<code>0/2 == 0),安全 - 示例:
for (size_t i = 0; i < s.length() / 2; ++i) { std::swap(s[i], s[s.length() - 1 - i]); }
反转 UTF-8 字符串会出问题
std::reverse 和手动交换都按字节操作,对 UTF-8 编码的多字节字符(如中文、emoji)会导致乱码,因为单个 Unicode 字符可能占 2–4 字节,字节级翻转会破坏编码结构。
这不是 C++ 的缺陷,而是字符串编码层面的问题;标准库不感知字符语义。
- 若需真正“反转字符”,得先做 UTF-8 解码,按 code point 切分,再反转,最后重新编码——需要第三方库(如
utf8cpp)或自己实现解码逻辑 - 简单判断:如果输入含非 ASCII 字符(
ch > 127),且你观察到反转后输出异常(如显示 或截断),大概率是 UTF-8 字节序被破坏 - 命令行终端、文件读写、网络传输中,UTF-8 是常见默认,这点极易被忽略
性能和 const 正确性要兼顾
反转操作本质是就地修改,所以函数签名通常不该接受 const std::string&——除非你明确想拷贝一份再反转。
在性能敏感路径(如高频日志处理、嵌入式解析),要注意 std::string 的 small string optimization(SSO)是否生效,但反转本身复杂度始终是 O(n),与容量无关。
- 避免无谓拷贝:
std::string reversed = s; std::reverse(reversed.begin(), reversed.end());比auto reversed = std::string(s.rbegin(), s.rend());少一次构造,但后者更清晰表达“创建新反转串”意图 - 如果原字符串很大且后续不再使用,可考虑
std::move后反转,但std::reverse不移动数据,只是重排,所以收益有限 - 不要为了“函数式风格”强行写成
return std::string(s.rbegin(), s.rend())就完事——它看起来简洁,但掩盖了是否真需要新对象的语义
实际项目里,95% 的场景用 std::reverse 就够了,但只要字符串可能含非 ASCII 内容,就得停下来问一句:这里反转的到底该是字节,还是字符。

















