17370845950

C++ string length和size区别 C++字符串长度获取方法辨析【细节】
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() 提前截断。

例如:

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() 还可能因 loca

    le 或宽字符宏定义引发隐式转换问题
  • 性能上,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 可安全访问,其余全是边界陷阱。