length() 和 size() 在 std::string 中完全等价,均返回字符个数(不含'\0'),类型为size_t,底层实现相同;二者均不反映容量、内存大小或Unicode码点数,且不可用strlen替代。

length() 和 size() 在 std::string 中完全等价
二者都是 size_t 类型的无参成员函数,返回字符串当前字符个数(不含终止符 '\0'),底层调用同一实现。标准明确要求 length() == size(),任何合规编译器都必须满足这点。
常见误解是认为 length() 算“语义长度”、size() 算“内存大小”,实际完全错误——两者都不涉及容量(capacity)、不计算内部缓冲区冗余空间,也不处理 UTF-8 多字节字符的逻辑长度。
- 对空字符串
s = "",s.length()和s.size()都返回0 - 对
s = "café"(UTF-8 编码为 5 字节:c a f é → c a f c 3 a9),s.length()返回5,不是 Unicode 码点数 4 - 调用
s.reserve(100)后,s.size()仍为原值,不会变成 100
不要用 strlen(s.c_str()) 获取 std::string 长度
strlen() 是 C 风格函数,依赖 '\0' 终止符;而 std::string 允许存储含 '\0' 的二进制数据,此时 c_str() 虽保证以 '\0' 结尾,但中间可能已有 '\0',导致 strlen() 提前截断。
例如:
立即学习“C++免费学习笔记(深入)”;
std::string s = "abc\0def"; // 实际含 7 个字符(含中间 \0) std::cout << s.length(); // 输出 7 std::cout << strlen(s.c_str()); // 输出 3 —— 错误!
- 仅当你能 100% 确保字符串不含 '\0' 且只用于 C 接口互操作时,才考虑
c_str()+strlen() - 跨平台代码中,
strlen()还可能因 locale 或宽字符宏定义引发隐式转换问题 - 性能上,
s.length()是 O(1) 直接读成员变量,strlen()是 O(n) 遍历,无必要开销
获取真实 Unicode 字符数需额外处理
length() 和 size() 返回的是字节数,不是用户感知的“字符数”。对 UTF-8 字符串(如中文、emoji),一个字符占多个字节,直接使用会严重低估显示宽度或切分位置。
没有标准库函数能直接完成此转换,必须借助外部库或手动解析 UTF-8 编码:
- ICU 库提供
u_countChar32(),健壮但引入依赖 - libutf8cpp 或 utf8.h(单头)可轻量解析:
utf8::distance(s.begin(), s.end()) - 自己写 UTF-8 解析要处理 1~4 字节序列、校验非法码位(如 0xFFFD 替换符场景)
- 注意:Windows 控制台默认 ANSI 编码,即使源字符串是 UTF-8,输出也可能乱码,长度计算结果与显示效果脱节
capacity() 和 max_size() 容易被混淆
size() 是已用长度,capacity() 是当前分配的缓冲区总字节数(≥ size()),max_size() 是该对象理论上能容纳的最大字节数(通常接近 SIZE_MAX/sizeof(char))。
- 执行
s += "xxx"可能触发重分配,使capacity()突增(如从 15→31),但size()只增 3 -
max_size()极少用于业务逻辑,多见于防御性检查(如防止恶意构造超长字符串) - 误把
capacity()当作长度用,会导致 buffer overflow(如用memcpy(buf, s.data(), s.capacity()))
真正需要关注的只有 size()(或 length())——它告诉你有多少个有效 char 可安全访问,其余全是边界陷阱。










