跳到主要内容
C++ string 类详解:接口使用与底层模拟实现 | 极客日志
C++ 算法
C++ string 类详解:接口使用与底层模拟实现 综述由AI生成 C++ string 类是标准库中管理字符串的核心工具,相比 C 语言 char 数组更安全便捷。梳理了 string 的常用接口,涵盖构造、容量控制、访问遍历及修改操作,并对比了不同编译器下的内部结构差异。重点讲解了浅拷贝与深拷贝的区别,通过模拟 String 类实现展示了析构函数、拷贝构造函数及赋值运算符重载的关键逻辑,帮助开发者理解内存管理与资源所有权机制。
片刻 发布于 2026/3/23 更新于 2026/5/3 4 浏览为什么学习 string 类?
C 语言中的字符串
C 语言中,字符串是以 \0 结尾的字符集合。标准库提供了 str 系列函数,但这些函数与字符串对象分离,不符合 OOP 思想,且底层空间需用户自行管理,容易越界。
在算法竞赛及常规开发中,为了安全、便捷,基本都使用 std::string 类。
标准库中的 string 类
string 类概述
使用 string 类时,需包含 <string> 头文件并使用 using namespace std;。
auto 和范围 for
auto 关键字
C++11 引入 auto 作为类型指示符,由编译器推导变量类型。声明指针时 auto 与 auto* 无区别,但引用类型必须加 &。同一行声明多个变量时类型必须一致,否则报错。auto 不能作为函数参数,建议谨慎用作返回值,不能直接声明数组。
#include <iostream>
#include <typeinfo>
using namespace std;
int func1 () { return 10 ; }
void func2 (auto a) {}
auto func3 () { return 3 ; }
int main () {
int a = 10 ;
auto b = a;
auto c = 'a' ;
auto d = func1 ();
cout << (b). () << endl;
cout << (c). () << endl;
cout << (d). () << endl;
x = ;
y = &x;
* z = &x;
& m = x;
;
}
typeid
name
typeid
name
typeid
name
int
10
auto
auto
auto
return
0
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main () {
std::map<std::string, std::string> dict = {
{ "apple" , "苹果" },
{ "orange" , "橙子" },
{ "pear" , "梨" }
};
auto it = dict.begin ();
while (it != dict.end ()) {
cout << it->first << ":" << it->second << endl;
++it;
}
return 0 ;
}
范围 for 循环
C++11 引入基于范围的 for 循环,自动处理迭代,本质仍是迭代器遍历。适用于数组和容器。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main () {
int array[] = { 1 , 2 , 3 , 4 , 5 };
for (int i = 0 ; i < sizeof (array) / sizeof (array[0 ]); ++i) {
array[i] *= 2 ;
}
for (auto & e : array) e *= 2 ;
for (auto e : array) cout << e << " " ;
cout << endl;
string str ("hello world" ) ;
for (auto ch : str) {
cout << ch << " " ;
}
cout << endl;
return 0 ;
}
string 类的常用接口说明
1. string 类对象的常见构造 #include <iostream>
#include <string>
using namespace std;
void test1 () {
string s1;
string s2 ("hello,world" ) ;
string s3 (3 , 'a' ) ;
string s4 = s2;
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
}
int main () {
test1 ();
return 0 ;
}
2. string 类对象的容量操作 函数名称 功能说明 size(重点)返回字符串有效字符长度 length返回字符串有效字符长度 capacity返回空间总大小 empty(重点)检测是否为空串 clear(重点)清空有效字符,不释放空间 reserve(重点)为字符串预留空间 resize(重点)改变有效字符个数
#include <iostream>
#include <string>
using namespace std;
int main () {
string s1 = "hello,world!" ;
cout << s1. size () << endl;
cout << s1.l ength() << endl;
cout << s1. empty () << endl;
cout << "clear 前的实际空间个数" << endl;
cout << s1. capacity () << endl;
s1. clear ();
cout << "clear 后的空间个数" << endl;
cout << s1. capacity () << endl;
cout << s1. empty () << endl;
s1. reserve (20 );
cout << "reserve 后的实际空间个数" << endl;
cout << s1. capacity () << endl;
cout << s1. size () << endl;
s1. resize (10 , 'a' );
cout << s1 << endl;
return 0 ;
}
注意: size() 与 length() 原理相同,统一接口习惯多用 size()。clear() 仅清空内容,不改变底层容量。resize(n) 若增大则可能扩容,减小则不释放空间;resize(n, c) 指定填充字符。reserve() 仅预留空间,不改变有效元素个数。
3. string 类对象的访问及遍历操作 #include <iostream>
#include <string>
using namespace std;
int main () {
string s;
s += "hello,world" ;
cout << "范围 for 遍历 s:" << endl;
for (auto & e : s) {
cout << e << " " ;
}
cout << endl;
cout << "正向迭代器遍历 s:" << endl;
for (auto i = s.begin (); i != s.end (); i++) {
cout << *i << " " ;
}
cout << endl;
cout << "逆向迭代器遍历 s" << endl;
for (auto i = s.rbegin (); i != s.rend (); i++) {
cout << *i << " " ;
}
cout << endl;
return 0 ;
}
4. string 类对象的修改操作 函数名称 功能说明 push_back末尾插入字符 append追加字符串 operator+=(重点)追加字符串或字符 c_str(重点)返回 C 格式字符串 (const char*) find + npos(重点)查找字符/子串位置 rfind反向查找 substr截取子串
#include <iostream>
#include <string>
using namespace std;
int main () {
string s1;
s1. push_back ('c' );
char a = 'd' ;
s1. push_back (a);
cout << s1 << endl;
return 0 ;
}
#include <iostream>
#include <string>
using namespace std;
int main () {
string s = "hello,world" ;
string s2 = "llo" ;
cout << s.find (s2) << endl;
cout << s.find ("wor" ) << endl;
cout << s.find ("wor" , 5 , 2 ) << endl;
cout << s.find ('l' ) << endl;
cout << s.find ('l' , 5 ) << endl;
cout << s.find ("www" ) << endl;
return 0 ;
}
#include <iostream>
#include <string>
using namespace std;
int main () {
string s = "hello,world" ;
cout << s.substr (2 , 3 ) << endl;
return 0 ;
}
注意: 尾部追加字符时,push_back、append、+= 性能差异不大,通常 += 更简洁。预估字符数量时,可先用 reserve 预留空间以减少扩容开销。
5. string 类非成员函数 输入输出运算符重载通常在模拟实现中完成。getline 是 std 命名空间下的全局函数,用于读取整行(含空格)。
#include <iostream>
#include <string>
using namespace std;
int main () {
string s;
cout << "cin >> s 输入效果:" << endl;
cin >> s;
cout << s << endl;
cout << "getline 输入效果:" << endl;
getline (cin, s);
cout << s << endl;
return 0 ;
}
注意: cin >> s 后缓冲区残留换行符会影响后续 getline,需用 cin.ignore() 清除。
6. VS 和 g++ 下 string 结构的说明 VS 下结构:
32 位平台下占 28 字节。内部使用联合体存储:短字符串(<16 字符)使用内部固定数组(SSO),长字符串指向堆空间。包含长度、容量字段及额外指针。
g++ 下结构:
采用写时拷贝(Copy-On-Write)。对象占 4 字节,仅含一个指针指向堆空间。堆空间包含长度、容量、引用计数等信息。
7. string 函数接口的应用 class Solution {
public :
bool isLetter (char ch) {
if (ch >= 'a' && ch <= 'z' ) return true ;
if (ch >= 'A' && ch <= 'Z' ) return true ;
return false ;
}
string reverseOnlyLetters (string S) {
if (S.empty ()) return S;
size_t begin = 0 , end = S.size () - 1 ;
while (begin < end) {
while (begin < end && !isLetter (S[begin])) ++begin;
while (begin < end && !isLetter (S[end])) --end;
swap (S[begin], S[end]);
++begin;
--end;
}
return S;
}
};
class Solution {
public :
int firstUniqChar (string s) {
int count[256 ] = {0 };
int size = s.size ();
for (int i = 0 ; i < size; ++i) count[s[i]] += 1 ;
for (int i = 0 ; i < size; ++i)
if (1 == count[s[i]]) return i;
return -1 ;
}
};
class Solution {
public :
string addStrings (string num1, string num2) {
int end1 = num1. size () - 1 ;
int end2 = num2. size () - 1 ;
int value1 = 0 , value2 = 0 , next = 0 ;
string addret;
while (end1 >= 0 || end2 >= 0 ) {
if (end1 >= 0 ) value1 = num1[end1--] - '0' ;
else value1 = 0 ;
if (end2 >= 0 ) value2 = num2[end2--] - '0' ;
else value2 = 0 ;
int valueret = value1 + value2 + next;
if (valueret > 9 ) {
next = 1 ;
valueret -= 10 ;
} else {
next = 0 ;
}
addret += (valueret + '0' );
}
if (next == 1 ) addret += '1' ;
reverse (addret.begin (), addret.end ());
return addret;
}
};
string 类的模拟实现
经典的 string 类问题 面试中常要求模拟实现 string 类,核心在于构造、拷贝构造、赋值运算符重载及析构函数。
class String {
public :
String (const char * str = "" ) {
if (nullptr == str) {
assert (false );
return ;
}
_str = new char [strlen (str) + 1 ];
strcpy (_str, str);
}
~String () {
if (_str) {
delete [] _str;
_str = nullptr ;
}
}
private :
char * _str;
};
void TestString () {
String s1 ("hello bit!!!" ) ;
String s2 (s1) ;
}
程序结束时 s1 和 s2 会重复释放同一块内存,导致崩溃。这是因为编译器合成的默认拷贝构造只是简单的值拷贝,未处理资源管理。
浅拷贝与深拷贝 浅拷贝 :直接复制成员变量。若成员包含动态资源,会导致多对象共享同一资源,析构时重复释放。
深拷贝 :每个对象拥有独立资源。涉及资源管理的类,必须显式定义拷贝构造函数、赋值运算符重载及析构函数。
传统版写法的 String 类 class String {
public :
String (const char * str = "" ) {
if (nullptr == str) {
assert (false );
return ;
}
_str = new char [strlen (str) + 1 ];
strcpy (_str, str);
}
String (const String& s) : _str(new char [strlen (s._str) + 1 ]) {
strcpy (_str, s._str);
}
String& operator =(const String& s) {
if (this != &s) {
char * pStr = new char [strlen (s._str) + 1 ];
strcpy (pStr, s._str);
delete [] _str;
_str = pStr;
}
return *this ;
}
~String () {
if (_str) {
delete [] _str;
_str = nullptr ;
}
}
private :
char * _str;
};
现代版写法的 String 类 class String {
public :
String (const char * str = "" ) {
if (nullptr == str) {
assert (false );
return ;
}
_str = new char [strlen (str) + 1 ];
strcpy (_str, str);
}
String (const String& s) : _str(nullptr ) {
String strTmp (s._str) ;
swap (_str, strTmp._str);
}
String& operator =(String s) {
swap (_str, s._str);
return *this ;
}
~String () {
if (_str) {
delete [] _str;
_str = nullptr ;
}
}
private :
char * _str;
};
写时拷贝 (了解) 在浅拷贝基础上增加引用计数。构造时计数为 1,每增加一个对象引用则计数加 1,销毁时减 1。仅当计数为 1 时才释放资源。这避免了不必要的深拷贝开销。
string 类的模拟实现 (完整示例) #pragma once
#include <iostream>
#include <cstring>
#include <cassert>
using namespace std;
class mystring {
public :
mystring (const char * s = "" ) {
if (s == nullptr ) {
assert (false );
return ;
}
_str = new char [strlen (s) + 1 ];
strcpy (_str, s);
_capacity = _size = strlen (s);
}
mystring (const mystring& s) {
_str = new char [s._capacity + 1 ];
strcpy (_str, s._str);
_size = s._size;
_capacity = s._capacity;
}
~mystring () {
delete [] _str;
_str = nullptr ;
_size = _capacity = 0 ;
}
mystring& operator =(const mystring& s) {
delete [] _str;
_str = new char [strlen (s._str) + 1 ];
strcpy (_str, s._str);
_size = s._size;
_capacity = s._capacity;
return *this ;
}
mystring operator +(const mystring& s) const {
mystring strtmp = *this ;
int newlenth = strlen (s._str) + strlen (_str) + 1 ;
if (newlenth > strtmp._capacity) {
char * newchar = new char [newlenth * 2 ];
strcpy (newchar, strtmp._str);
delete [] strtmp._str;
strtmp._str = newchar;
strtmp._capacity = newlenth * 2 ;
}
strcat (strtmp._str, s._str);
strtmp._size = newlenth - 1 ;
return strtmp;
}
mystring& operator +=(const mystring& s) {
mystring strtmp = s;
*this = (*this + strtmp);
return *this ;
}
void swap (mystring& s) {
std::swap (_str, s._str);
std::swap (_size, s._size);
std::swap (_capacity, s._capacity);
}
void print () const {
for (int i = 0 ; i < _size; i++) {
printf ("%c" , _str[i]);
}
printf ("\n" );
}
private :
char * _str;
int _size;
int _capacity;
};
ostream& operator <<(ostream& out, const mystring& s) {
s.print ();
return out;
}
istream& operator >>(istream& in, mystring& s) {
int i = 0 ;
char ch;
while (in.get (ch) && ch != ' ' && ch != '\n' ) {
s._str[i++] = ch;
}
s._str[i] = '\0' ;
s._size = i;
return in;
}
从手动计算长度、处理内存溢出的痛点,到使用 std::string 一行代码实现拼接查找,再到亲手拆解其动态扩容、深拷贝的底层逻辑,string 类的学习本质上是对 C++ 封装思想的实践。它把复杂的内存管理藏在底层,把简洁的接口留给开发者,既解决了 C 语言字符串的问题,也为后续 STL 容器的学习打下基础。
相关免费在线工具 加密/解密文本 使用加密算法(如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