🐸 青蛙编程网
首页 / C++ / STL / 3. string

string:字符串处理

这是什么:std::string——C++ 里装文字的容器,能拼、能切、能查,内存全自动帮你管。

为什么用:上一章的 vector 只会装数字,那名字、句子、文件路径这些文字怎么办?用 char 数组手拼又长又容易越界,string 一行就能搞定,用起来和 vector 一个路数。

如何用:声明一个 std::string 就能上手,本章先把拼接、长度这些基本操作过一遍,再练 substr 切片和 find 查找。

定义与拼接

#include <iostream>
#include <string>

int main() {
    std::string who = "小青蛙";
    std::cout << "你好," + who + "!" << std::endl;  // 拼接:直接 +

    std::string word = "frog";
    std::cout << word.length() << std::endl;  // 长度
    std::cout << word[0] << std::endl;        // 首字符
    return 0;
}

你会看到:

你好,小青蛙!
4
f

拼接就是 +,长度用 length(),下标从 0 起取单个字符——全是你熟悉的味道。

⚠️ 一个中文特有的坑:length() 数的是字节。UTF-8 编码里一个常用汉字占 3 个字节,所以 "小青蛙" 的 length() 是 9 不是 3。入门阶段记住这个坑,以后遇到"长度对不上",先想到它。

汉字长度实验

#include <iostream>
#include <string>

int main() {
    std::string s = "小青蛙";
    std::cout << s.length() << std::endl;  // 9(3 个汉字 × 3 字节),不是 3
    std::cout << s.size() << std::endl;    // size() 和 length() 一样,也是 9
    return 0;
}

切片:substr

Python 有切片,string 有 substr(起点, 个数):

#include <iostream>
#include <string>

int main() {
    std::string file = "frog.png";

    std::cout << file.substr(5) << std::endl;      // 从下标 5 取到结尾
    std::cout << file.substr(0, 4) << std::endl;   // 从 0 起取 4 个
    std::cout << "点在第 " << file.find(".") << " 位" << std::endl;
    return 0;
}

你会看到:

png
frog
点在第 4 位

查找:find

find 返回子串第一次出现的下标;找不到时返回特殊值 npos,所以查找前先比一比:

#include <iostream>
#include <string>

int main() {
    std::string file = "frog.png";

    if (file.find(".png") != std::string::npos) {
        std::cout << "是图片文件" << std::endl;
    } else {
        std::cout << "不是图片文件" << std::endl;
    }
    return 0;
}

你会看到:

是图片文件

查找与替换:更多用法

#include <iostream>
#include <string>

int main() {
    std::string s = "hello world";

    // 查找子串位置
    std::cout << s.find("world") << std::endl;  // 6

    // 替换:从位置 6 开始,替换 5 个字符为 "cpp"
    s.replace(6, 5, "cpp");
    std::cout << s << std::endl;  // hello cpp

    // 插入:在位置 5 插入 ", "
    s.insert(5, ", ");
    std::cout << s << std::endl;  // hello, cpp

    // 删除:从位置 5 开始删除 7 个字符
    s.erase(5, 7);
    std::cout << s << std::endl;  // hello
    return 0;
}

和 char[] 的恩怨

C 语言里字符串是 char 数组,结尾还要补个 '\0',一不留神就越界;C++ 的 string 把这些全自动化了。新代码放心用 string,将来读老代码时再会会 char[] 不迟。

常用操作速查

操作 干什么 备注
s1 + s2 拼接 直接拼字面量也行
s.length() / s.size() 长度(字节数) 中文一个字占 3 字节
s[i] 取第 i 个字符 下标从 0 起
s.substr(a, n) 从 a 取 n 个;省略 n 取到尾 类似切片
s.find(t) 找子串,返回下标 找不到返回 npos
s.replace(a, n, t) 从 a 开始替换 n 个为 t
s.insert(a, t) 在位置 a 插入 t
s.erase(a, n) 从 a 开始删除 n 个

记忆口诀

拼接用加号,长度 length 数;substr 切片,find 找不到是 npos。

❓ 常见问题

Q1:std::string 和 C 风格字符串 char[] 有什么区别?

char[] 是固定大小的数组,要手动管理 '\0' 结尾,容易越界;std::string 自动管理内存,可动态增长,有丰富的成员函数,更安全更方便。

Q2:length() 返回的是字符数还是字节数?

是字节数。一个英文字母 1 字节,一个常用汉字 UTF-8 编码 3 字节。想获取"字符数"(把一个汉字算 1 个),需要更复杂的处理,入门阶段先记住"按字节算"这个坑。

Q3:find 找不到返回什么?

返回 std::string::npos,这是一个很大的无符号数值,表示"未找到"。比较时用 != std::string::npos 判断找到,== std::string::npos 判断没找到。

⚠️ 新手翻车现场

翻车一:中文长度对不上

std::string s = "小青蛙";
std::cout << s.length();  // 打印 9,不是 3

问题:length() 数字节,3 个汉字 × 3 字节 = 9。

修正:入门阶段先记住这个坑;需要精确字符数时,可用第三方库或按字符编码逐个解码。

翻车二:find 找不到却直接当下标用

std::string s = "hello";
size_t pos = s.find("xyz");  // 返回 npos
std::cout << s[pos];         // 越界,未定义行为

问题:找不到时 pos 是 npos(一个很大的数),拿它当下标访问会越界。

修正:先判断 if (pos != std::string::npos) 再用。

翻车三:substr 参数超出长度

std::string s = "hi";
s.substr(0, 100);  // 第二个参数大于剩余长度

问题:substr 允许 n 超过剩余长度,实际只取到字符串结尾,不会报错。但如果起点 a 超过长度,会抛出 out_of_range 异常。

修正:起点必须在有效范围内,n 可以大(自动截断到结尾)。

🎯 什么时候用 string

  • 处理文本:拼接、切片、查找、替换
  • 需要动态长度的字符序列
  • 替代 C 风格的 char[],避免手动内存管理

📝 本章小结

  • std::string 能拼(+)、切(substr)、查(find)、改(replace/insert/erase)
  • length()/size() 返回字节数,中文一个字 3 字节,记住这个坑
  • find 找不到返回 npos,用前先判断
  • 新代码优先用 string,避免 char[] 的手动内存管理
  • 记忆口诀:拼接用加号,长度 length 数;substr 切片,find 找不到是 npos。

动手改

  1. 把 file 换成 "yourname.jpg",分别取出主名和后缀
  2. 用 find 找出字母 o 在 "frog" 里的位置并打印
  3. 拼一句自我介绍:把名字和一个年龄数字(用 std::to_string(age) 转成字符串)用 + 连起来输出
  4. 用 replace 把 "hello world" 里的 world 换成 cpp

下一章:map 与 set,键值对和去重神器来了 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。