跳到主要内容
C++ string 类全面解析 | 极客日志
C++ 算法
C++ string 类全面解析 综述由AI生成 C++ string 类是标准库中封装字符串存储和操作的核心工具,解决了 C 语言字符串的安全性及内存管理问题。详细讲解了 string 类的构造函数、容量操作、元素访问、修改方法及常用接口,对比了不同编译器下的实现差异(如 SSO 和写时拷贝),并通过模拟实现深拷贝与浅拷贝问题阐述了底层原理。此外,结合反转字母、大数相加等实战案例,提供了性能优化建议与最佳实践。
laoliangsh 发布于 2026/2/4 更新于 2026/6/3 5.3K 浏览C++ string 类全面解析
1. 为什么学习 string 类?
1.1 C 语言中的字符串局限性
在 C 语言中,字符串是以 \0 结尾的字符数组,这种表示方式存在几个明显的缺陷:
C 语言字符串的主要问题:
安全性问题 :容易发生缓冲区溢出,导致程序崩溃或安全漏洞
内存管理复杂 :需要手动管理内存分配和释放,容易造成内存泄漏
功能有限 :标准库函数功能相对基础,复杂的字符串操作需要自行实现
不符合面向对象思想 :数据与操作分离,不符合现代编程范式
char str[10 ];
strcpy (str, "这个字符串太长了会导致溢出" );
1.2 实际应用需求
在现代编程中,字符串处理占据了极大的比重。无论是 Web 开发、数据处理还是系统编程,都离不开高效的字符串操作。string 类的出现正是为了解决 C 语言字符串的种种痛点。
面试题示例:
实践建议 :在 OJ 题目和实际开发中,string 类已成为字符串处理的首选工具,相比 C 字符串库函数更加安全高效。
2. 标准库中的 string 类
2.1 string 类基础
string 类是 C++ 标准库中用于表示和操作字符串的类,封装了字符串的存储和常见操作。
基本用法:
#include <string>
#include <iostream>
using namespace std;
int main () {
string s1;
string s2 = "Hello" ;
string s3 ("World" ) ;
return 0 ;
}
2.2 C++11 新特性:auto 和范围 for
auto 关键字详解 auto 是 C++11 引入的类型推断关键字,让编译器自动推导变量类型。
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main () {
auto a = 10 ;
auto b = 3.14 ;
auto c = 'A' ;
int x = 100 ;
auto y = &x;
auto * z = &x;
auto & ref = x;
map<string, string> dict = {{"apple" , "苹果" }, {"banana" , "香蕉" }};
auto it2 = dict.begin ();
for (auto it = dict.begin (); it != dict.end (); ++it) {
cout << it->first << ": " << it->second << endl;
}
return 0 ;
}
必须初始化:auto x; // 错误
多变量声明必须类型一致:auto a=1, b=2.0; // 错误
不能用于函数参数(但可以用于返回值)
不能声明数组:auto arr[] = {1,2,3}; // 错误
范围 for 循环(Range-based for loop) 范围 for 提供了更简洁的遍历语法,特别适合容器遍历。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main () {
int arr[] = {1 , 2 , 3 , 4 , 5 };
for (int i = 0 ; i < sizeof (arr)/sizeof (arr[0 ]); ++i) {
cout << arr[i] << " " ;
}
cout << endl;
for (auto elem : arr) {
cout << elem << " " ;
}
cout << endl;
for (auto & elem : arr) {
elem *= 2 ;
}
string str = "Hello" ;
for (auto ch : str) {
cout << ch << " " ;
}
cout << endl;
return 0 ;
}
范围 for 的底层原理 :编译器会将范围 for 转换为基于迭代器的普通循环。
2.3 string 类常用接口详解
2.3.1 构造函数 构造函数 功能说明 示例 string()创建空字符串 string s1;string(const char* s)用 C 字符串构造 string s2("hello");string(size_t n, char c)n 个字符 c 组成的字符串 string s3(5, 'A'); // "AAAAA"string(const string& str)拷贝构造 string s4(s2);
void testConstructors () {
string s1;
string s2 ("Hello World" ) ;
string s3 (s2) ;
string s4 (10 , '*' ) ;
string s5 = "直接赋值" ;
cout << "s2: " << s2 << endl;
cout << "s4: " << s4 << endl;
}
2.3.2 容量操作 方法 功能 说明 size()/length()返回字符串长度 两者功能相同,推荐 size() capacity()返回分配的内存大小 通常 ≥ size() empty()判断是否为空 空返回 true,否则 false clear()清空内容 不释放内存,size=0 reserve(size_t n)预留空间 避免频繁重新分配 resize(size_t n, char c)调整大小 多出部分用 c 填充
void testCapacity () {
string str = "Hello" ;
cout << "长度:" << str.size () << endl;
cout << "容量:" << str.capacity () << endl;
cout << "是否为空:" << str.empty () << endl;
str.resize (10 , '!' );
cout << "调整后:" << str << endl;
str.reserve (100 );
cout << "预留后容量:" << str.capacity () << endl;
str.clear ();
cout << "清空后长度:" << str.size () << endl;
}
string s = "Hello" ;
s.resize (3 );
s.resize (8 , '!' );
s.resize (10 );
2.3.3 元素访问和遍历 void testTraversal () {
string str = "ABCDE" ;
for (size_t i = 0 ; i < str.size (); ++i) {
cout << str[i] << " " ;
}
cout << endl;
for (auto it = str.begin (); it != str.end (); ++it) {
cout << *it << " " ;
}
cout << endl;
for (auto rit = str.rbegin (); rit != str.rend (); ++rit) {
cout << *rit << " " ;
}
cout << endl;
for (auto ch : str) {
cout << ch << " " ;
}
cout << endl;
}
2.3.4 修改操作 方法 功能 示例 push_back(char c)尾部添加字符 str.push_back('!')append(const string& str)追加字符串 str.append(" World")operator+=追加(最常用) str += "!!"insert(size_t pos, const string& str)插入字符串 str.insert(5, "插入")erase(size_t pos, size_t len)删除子串 str.erase(5, 2)replace(size_t pos, size_t len, const string& str)替换子串 str.replace(0, 5, "Hi")
void testModification () {
string str = "Hello" ;
str.push_back ('!' );
str.append (" World" );
str += "!!" ;
str.insert (6 , "C++ " );
str.erase (0 , 7 );
str.replace (4 , 5 , "String" );
cout << "最终结果:" << str << endl;
}
2.3.5 字符串操作 void testStringOperations () {
string str = "Hello World, Hello C++" ;
size_t pos1 = str.find ("Hello" );
size_t pos2 = str.find ("Hello" , 1 );
size_t pos3 = str.rfind ("Hello" );
string sub1 = str.substr (6 , 5 );
string sub2 = str.substr (6 );
string s1 = "apple" , s2 = "banana" ;
int result = s1. compare (s2);
cout << "find 结果:" << pos1 << ", " << pos2 << ", " << pos3 << endl;
cout << "子串:" << sub1 << ", " << sub2 << endl;
}
2.4 不同编译器下的 string 实现
VS 下的 string 实现(小字符串优化) Visual Studio 采用小字符串优化 (SSO) 策略:
16 字节缓冲区:长度<16 时使用栈空间
4 字节:字符串长度
4 字节:总容量
4 字节:其他信息
总计 28 字节
string shortStr = "short" ;
string longStr = "这是一个很长的字符串..." ;
g++ 下的 string 实现(写时拷贝) g++ 采用写时拷贝 (Copy-On-Write) 技术:
4 字节指针:指向堆上的结构体
结构体包含:长度、容量、引用计数、字符串数据
string s1 = "hello" ;
string s2 = s1;
s2[0 ] = 'H' ;
2.5 实战练习
示例 1:仅反转字母 class Solution {
public :
bool isLetter (char ch) {
return (ch >= 'a' && ch <= 'z' ) || (ch >= 'A' && ch <= 'Z' );
}
string reverseOnlyLetters (string s) {
if (s.empty ()) return s;
int left = 0 , right = s.size () - 1 ;
while (left < right) {
while (left < right && !isLetter (s[left])) ++left;
while (left < right && !isLetter (s[right])) --right;
if (left < right) {
swap (s[left], s[right]);
++left;
--right;
}
}
return s;
}
};
示例 2:字符串相加(大数加法) class Solution {
public :
string addStrings (string num1, string num2) {
int i = num1. size () - 1 , j = num2. size () - 1 ;
int carry = 0 ;
string result;
while (i >= 0 || j >= 0 || carry > 0 ) {
int digit1 = (i >= 0 ) ? num1[i--] - '0' : 0 ;
int digit2 = (j >= 0 ) ? num2[j--] - '0' : 0 ;
int sum = digit1 + digit2 + carry;
carry = sum / 10 ;
result.push_back ('0' + (sum % 10 ));
}
reverse (result.begin (), result.end ());
return result;
}
};
示例三:字符串最后一个单词的长度 #include <iostream>
using namespace std;
int main () {
string s;
getline (cin, s);
size_t pos = s.rfind (' ' );
cout << s.size () - (pos + 1 ) << endl;
}
getline 默认三个参数,输入两个时,默认最后一个是空。
3. string 类的模拟实现
3.1 浅拷贝问题
class String {
public :
String (const char * str = "" ) {
_str = new char [strlen (str) + 1 ];
strcpy (_str, str);
}
~String () {
delete [] _str;
}
private :
char * _str;
};
void testProblem () {
String s1 ("hello" ) ;
String s2 (s1) ;
}
3.2 深拷贝实现
传统版 String 类 class String {
public :
String (const char * str = "" ) {
if (str == nullptr ) str = "" ;
_str = new char [strlen (str) + 1 ];
strcpy (_str, str);
}
String (const String& other) {
_str = new char [strlen (other._str) + 1 ];
strcpy (_str, other._str);
}
String& operator =(const String& other) {
if (this != &other) {
char * temp = new char [strlen (other._str) + 1 ];
strcpy (temp, other._str);
delete [] _str;
_str = temp;
}
return *this ;
}
~String () {
delete [] _str;
}
private :
char * _str;
};
现代版 String 类(更优雅) class String {
public :
String (const char * str = "" ) {
if (str == nullptr ) str = "" ;
_str = new char [strlen (str) + 1 ];
strcpy (_str, str);
}
String (const String& other) : _str(nullptr ) {
String temp (other._str) ;
swap (_str, temp._str);
}
String& operator =(String other) {
swap (_str, other._str);
return *this ;
}
~String () {
delete [] _str;
}
private :
char * _str;
};
3.3 写时拷贝(Copy-On-Write) 写时拷贝是一种优化技术,在读取时共享数据,在修改时才进行实际拷贝。
多个对象共享同一数据
引用计数跟踪共享者数量
当有修改操作时,才进行实际拷贝
class CowString {
private :
struct StringData {
char * data;
int refCount;
StringData (const char * str) {
data = new char [strlen (str) + 1 ];
strcpy (data, str);
refCount = 1 ;
}
~StringData () {
delete [] data;
}
};
StringData* _data;
public :
};
4. 最佳实践和性能建议
4.1 字符串操作优化
string result;
for (int i = 0 ; i < 1000 ; ++i) {
result += "data" ;
}
string result;
result.reserve (5000 );
for (int i = 0 ; i < 1000 ; ++i) {
result += "data" ;
}
4.2 选择合适的方法 string str = "hello" ;
str.push_back ('!' );
str.append (1 , '!' );
str += '!' ;
size_t pos1 = str.find ('e' );
size_t pos2 = str.find ("ll" );
size_t pos3 = str.rfind ('l' );
5. 总结 string 类是 C++ 中最重要的工具类之一,它:
解决了 C 字符串的安全性问题 :自动内存管理,防止缓冲区溢出
提供了丰富的操作方法 :查找、替换、分割等常用操作一应俱全
具有高效的实现 :小字符串优化、写时拷贝等技术提升性能
支持现代 C++ 特性 :与 STL 算法、范围 for 等完美配合
string result;
result.reserve (5000 );
for (int i = 0 ; i < 1000 ; ++i) {
result += "data" ;
}
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online