C++ 字符串

在 C++ 中,字符串主要有两种表现形式:

  1. C 风格字符串(C‑string):以 '\0'(null 字符)结尾的字符数组。
  2. std::string:C++ 标准库提供的、封装了动态长度管理的字符串类。

下面分别介绍它们的特点和用法,并给出常用操作的示例。


1. C 风格字符串

char s1[] = "Hello";        // 编译器自动加上末尾的 '\0',等价于 {'H','e','l','l','o','\0'}
char* s2 = "World";         // 字面量存放在只读区,不能修改内容
  • 优点
    • 兼容 C 语言接口,例如 printf("%s", s1);
    • 控制粒度细,可在底层优化。
  • 缺点
    • 必须自己管理长度,容易发生越界或忘记 '\0'
    • 操作繁琐,常要用到 <cstring> 里的函数,如 strlenstrcpystrcatstrcmp 等:#include <cstring> char dest[20]; strcpy(dest, s1); // 拷贝 strcat(dest, " "); // 拼接 strcat(dest, s2); size_t len = strlen(dest); // 获取长度 (不含 '\0')

2. std::string(推荐使用)

std::string 定义在 <string> 头文件中,是对可变长字符序列的封装,使用更安全、简便。

#include <string>
#include <iostream>
using namespace std;

int main() {
    string a = "Hello";
    string b = "World";
    string c = a + " " + b;       // 拼接
    cout << c << " (长度: " << c.size() << ")\n";

    // 访问字符
    for (size_t i = 0; i < c.size(); ++i) {
        cout << c[i];
    }
    cout << "\n";

    // 查找与替换
    auto pos = c.find("World");   // 返回子串在 c 中的起始位置,找不到返回 npos
    if (pos != string::npos) {
        c.replace(pos, 5, "C++"); // 用 "C++" 替换长度为 5 的子串
    }
    cout << "替换后: " << c << "\n";
}

常用成员函数

操作函数说明
获取长度size() / length()返回字符数(不含末尾 \0
判断是否为空empty()空则返回 true
访问字符operator[] / at()at() 有范围检查,越界会抛异常
拼接operator+ / append()返回新字符串或在原串尾部追加
比较compare() / ==, <, > 等比较字符串大小或字典序
查找find()rfind()find_first_of()查找子串或字符集
插入insert(pos, str)在 pos 位置插入字符串
替换replace(pos, len, str)替换从 pos 开始、长度为 len 的子串
删除erase(pos, len)删除从 pos 开始、长度为 len 的字符
子串substr(pos, len)返回从 pos 开始、长度为 len 的新字符串
清空clear()清空内容
C 风格访问c_str()返回以 '\0' 结尾的 const char*

3. 进阶:std::string_view

C++17 引入了 std::string_view,它是对已有字符序列的一种轻量只读视图,不负责管理内存,适合高性能场景中避免拷贝:

#include <string_view>
#include <iostream>
using namespace std;

void print_view(string_view sv) {
    cout << sv << " (长度: " << sv.size() << ")\n";
}

int main() {
    string s = "Hello, C++17!";
    print_view(s);                   // 可以直接传入 std::string
    print_view("Literal");           // 也可传入字面量
}

注意string_view 不以 '\0' 结尾,它只是记录起始地址和长度;函数返回或在视图失效后勿再使用。


4. 宽字符与 Unicode 支持

  • std::wstring:宽字符版本,通常每字符占 wchar_t(Windows 上 2 字节,Linux 上 4 字节)。
  • C++20 提供了 std::u8stringstd::u16stringstd::u32string,分别对应 UTF‑8、UTF‑16、UTF‑32 编码的字符串。
u8string u8 = u8"你好,世界";      // UTF‑8 编码
u16string u16 = u"Привет";        // UTF‑16 编码

使用这些类型时,要结合对应的转换库(如 <codecvt>,或使用 ICU、Boost.Locale 等)来进行编码转换和处理。


5. 性能优化建议

  • 避免频繁拼接:大量拼接时可预先 reserve() 足够容量,减少多次分配。
  • 传参优先使用 const string& 或 string_view:避免不必要的拷贝。
  • 小字符串优化(SSO):大多数实现中,std::string 会在本地缓冲区存储短字符串(通常 ≤15 字节)以减少堆分配。

小结

  • 优先使用 std::string,它安全、易用且功能丰富。
  • 对性能有严格要求或仅需读访问时,可考虑 std::string_view
  • 需要兼容 C 接口或在底层优化时,可使用 C 风格字符串。
  • 若处理 Unicode,选用相应的宽字符串或 UTF 专用 string 类型,并配合合适的转换库。

掌握上述用法,便能在大多数 C++ 项目中高效、安全地处理字符串。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注