C++ STL 核心:string 从入门到精通(面试+源码+OJ实战)
标签 :C++、STL、string、C++面试、C++基础、后端开发
摘要:本文全面讲解 C++ string 类,包含使用方法、遍历技巧、容量操作、VS/GCC 底层结构、深浅拷贝、写时拷贝、string 模拟实现与高频 OJ 题,适合面试备战与工程开发。
文章目录
- [C++ STL 核心:string 从入门到精通(面试+源码+OJ实战)](#C++ STL 核心:string 从入门到精通(面试+源码+OJ实战))
-
- [0 前言](#0 前言)
- [1 为什么要学 string?](#1 为什么要学 string?)
-
- [1.1 C 语言字符串的痛点](#1.1 C 语言字符串的痛点)
- [1.2 现实需求](#1.2 现实需求)
- [2 使用 string 的前置准备](#2 使用 string 的前置准备)
- [3 C++11 神器:auto + 范围 for(string 遍历必备)](#3 C++11 神器:auto + 范围 for(string 遍历必备))
-
- [3.1 auto 类型推导](#3.1 auto 类型推导)
- [3.2 范围 for(最简洁遍历)](#3.2 范围 for(最简洁遍历))
- [4 string 核心接口(高频必背)](#4 string 核心接口(高频必背))
-
- [4.1 构造函数(4 个重点)](#4.1 构造函数(4 个重点))
- [4.2 容量操作(面试必考)](#4.2 容量操作(面试必考))
- [4.3 遍历三剑客](#4.3 遍历三剑客)
- [4.4 修改与查找(开发最常用)](#4.4 修改与查找(开发最常用))
- [4.5 输入神器:getline](#4.5 输入神器:getline)
- [5 string 底层结构(面试高频)](#5 string 底层结构(面试高频))
-
- [5.1 VS 下:SSO 短字符串优化](#5.1 VS 下:SSO 短字符串优化)
- [5.2 GCC 下:COW 写时拷贝](#5.2 GCC 下:COW 写时拷贝)
- [6 面试必问:浅拷贝 vs 深拷贝](#6 面试必问:浅拷贝 vs 深拷贝)
-
- [6.1 浅拷贝(坑)](#6.1 浅拷贝(坑))
- [6.2 深拷贝(解决方案)](#6.2 深拷贝(解决方案))
- [6.3 现代写法(最优)](#6.3 现代写法(最优))
- [6.4 写时拷贝 COW](#6.4 写时拷贝 COW)
- [7 string 模拟实现(面试可直接手写)](#7 string 模拟实现(面试可直接手写))
- [8 OJ 实战:string 高频题(带答案)](#8 OJ 实战:string 高频题(带答案))
-
- [8.1 仅仅反转字母](#8.1 仅仅反转字母)
- [8.2 第一个只出现一次的字符](#8.2 第一个只出现一次的字符)
- [8.3 字符串相加(大数加法)](#8.3 字符串相加(大数加法))
- [9 string 核心要点总结(背会直接面试)](#9 string 核心要点总结(背会直接面试))
- [10 结尾 & 引流](#10 结尾 & 引流)
0 前言
不懂 string,别说你会用 C++。
string 是 STL 最基础、最常用、面试最高频的组件,没有之一。它解决了 C 语言字符串手动管理内存、接口零散、容易越界的痛点,是日常开发与笔试 OJ 的必备工具。
这篇文章带你从会用 → 懂原理 → 能手写 → 能面试,一次性吃透 string。
1 为什么要学 string?
1.1 C 语言字符串的痛点
- 以
\0结尾,内存必须自己管理,一不小心就越界、泄漏。 - str 系列函数与字符串分离,不符合 OOP 思想。
- 拼接、查找、扩容、比较都很麻烦。
1.2 现实需求
- OJ 字符串题默认用 string。
- 工作开发几乎不用 C 风格字符串。
- 面试必考:深浅拷贝、扩容、底层结构、c_str、迭代器失效。
2 使用 string 的前置准备
cpp
#include <string>
using namespace std;
3 C++11 神器:auto + 范围 for(string 遍历必备)
3.1 auto 类型推导
- 编译期自动推导类型,简化迭代器。
- 必须初始化。
- 不能做函数参数,不能定义数组。
- 定义引用必须加 &。
cpp
auto a = 10; // int
auto p = &a; // int*
auto& r = a; // int&
3.2 范围 for(最简洁遍历)
底层就是迭代器,自动遍历、自动结束。
cpp
string s = "hello";
for (auto& ch : s) { // 加 & 可修改
ch = toupper(ch);
}
for (auto ch : s) { // 只读
cout << ch << " ";
}
4 string 核心接口(高频必背)
4.1 构造函数(4 个重点)
cpp
string s1; // 空串
string s2("hello"); // C 字符串构造
string s3(5, 'a'); // n 个字符
string s4(s2); // 拷贝构造
4.2 容量操作(面试必考)
| 接口 | 作用 |
|---|---|
| size() / length() | 有效字符长度 |
| capacity() | 底层容量 |
| empty() | 是否为空 |
| clear() | 清空有效字符,不缩容 |
| reserve(n) | 预分配空间,不改 size |
| resize(n, c) | 改有效长度,多出来用 c 填充 |
一句话区分:
- reserve:只扩容,不改长度
- resize:改长度,会初始化
4.3 遍历三剑客
- 下标
[]
cpp
for (int i = 0; i < s.size(); ++i)
cout << s[i];
- 迭代器
cpp
string::iterator it = s.begin();
while (it != s.end()) {
cout << *it;
++it;
}
- 范围 for(C++11 首选)
cpp
for (auto ch : s) cout << ch;
4.4 修改与查找(开发最常用)
cpp
s += "hello"; // 拼接(优先用)
s += ' ';
s.append("world");
const char* cstr = s.c_str(); // 转 C 字符串
size_t pos = s.find('w'); // 查找
string sub = s.substr(0,5); // 截取
4.5 输入神器:getline
读取带空格的一整行:
cpp
string line;
getline(cin, line);
5 string 底层结构(面试高频)
5.1 VS 下:SSO 短字符串优化
- 32 位占 28 字节
- 长度 < 16:内部栈数组
- 长度 ≥ 16:堆空间
- 结构:联合体 + size + capacity + 指针
5.2 GCC 下:COW 写时拷贝
- 只占 4 字节(一个指针)
- 堆内存存:长度 + 容量 + 引用计数
- 读共享、写复制,高效省内存
6 面试必问:浅拷贝 vs 深拷贝
6.1 浅拷贝(坑)
- 默认拷贝构造只拷贝指针。
- 多个对象共用同一块内存。
- 析构时重复释放 → 程序崩溃。
6.2 深拷贝(解决方案)
- 每个对象独立开辟空间。
- 资源不共享,安全不冲突。
6.3 现代写法(最优)
cpp
String(const String& s) : _str(nullptr) {
String tmp(s._str);
swap(_str, tmp._str);
}
String& operator=(String s) {
swap(_str, s._str);
return *this;
}
6.4 写时拷贝 COW
- 浅拷贝 + 引用计数。
- 读共享,写才真正开空间。
- 拖延症式高效优化。
7 string 模拟实现(面试可直接手写)
cpp
class String {
public:
String(const char* str = "") {
if (str == nullptr) str = "";
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
// 深拷贝现代写法
String(const String& s) : _str(nullptr) {
String tmp(s._str);
swap(_str, tmp._str);
}
String& operator=(String s) {
swap(_str, s._str);
return *this;
}
~String() {
delete[] _str;
_str = nullptr;
}
const char* c_str() const { return _str; }
size_t size() const { return strlen(_str); }
char& operator[](sslocal://flow/file_open?url=size_t+i&flow_extra=eyJsaW5rX3R5cGUiOiJjb2RlX2ludGVycHJldGVyIn0=) { return _str[i]; }
private:
char* _str;
};
8 OJ 实战:string 高频题(带答案)
8.1 仅仅反转字母
cpp
string reverseOnlyLetters(string s) {
int l = 0, r = s.size()-1;
while (l < r) {
if (!isalpha(s[l])) l++;
else if (!isalpha(s[r])) r--;
else swap(s[l++], s[r--]);
}
return s;
}
8.2 第一个只出现一次的字符
cpp
int firstUniqChar(string s) {
int cnt[256] = {0};
for (auto ch : s) cnt[ch]++;
for (int i = 0; i < s.size(); ++i)
if (cnt[s[i]] == 1) return i;
return -1;
}
8.3 字符串相加(大数加法)
cpp
string addStrings(string num1, string num2) {
int i = num1.size()-1, j = num2.size()-1;
string res;
int carry = 0;
while (i >= 0 || j >= 0 || carry) {
int sum = carry;
if (i >= 0) sum += num1[i--] - '0';
if (j >= 0) sum += num2[j--] - '0';
carry = sum / 10;
res += (sum % 10) + '0';
}
reverse(res.begin(), res.end());
return res;
}
9 string 核心要点总结(背会直接面试)
- string 是管理字符数组的类,彻底替代 C 风格字符串。
- 优先用:
+=、size()、reserve、c_str()。 - 遍历三法:
[]、迭代器、范围 for。 - resize 改长度,reserve 改容量。
- 底层:VS 用 SSO,GCC 用 COW。
- 面试核心:浅拷贝/深拷贝、模拟实现、扩容机制。
- OJ 高频:反转、去重、字符串加法、回文判断。
10 结尾 & 引流
本文由 C++ 后端学习笔记整理,后续将持续更新:
- vector 底层原理与模拟实现
- list、map、unordered_map 深度剖析
- STL 面试 100 题
- 计算机基础、操作系统、网络
觉得有用请 点赞 + 收藏 + 关注,第一时间收到硬核干货更新!