跳到主要内容
C++ string 标准库核心用法详解 | 极客日志
C++ 算法
C++ string 标准库核心用法详解 综述由AI生成 C++ string 标准库封装了字符串操作,提供安全高效的解决方案。文章涵盖初始化方式、基础操作(长度、访问、修改、比较)、实用功能(查找、截取、替换、清空)及与 C 风格字符串转换。结合示例代码演示 API 用法,并包含模拟实现部分供进阶参考。
kaikai 发布于 2026/2/9 更新于 2026/6/1 21 浏览C++ string 标准库核心用法详解
在 C 语言中,我们处理字符串依赖于字符数组和一系列 C 标准库函数(如 strcpy、strcat、strcmp),不仅需要手动管理内存,还容易出现缓冲区溢出等问题。而 C++ 标准库提供的 std::string(简称 string),封装了字符串的所有操作,提供了安全、便捷、高效的字符串处理方案,是 C++ 开发中处理字符串的首选。
本文将从基础到实用,全面讲解 string 的核心用法,适合 C++ 初学者快速上手,也可作为日常开发的参考手册。
一、前期准备:使用 string 的前提
要使用 string,必须满足两个基本条件(缺一不可):
包含 string 头文件(注意无后缀 .h)
引用 std 命名空间(string 是标准库中的类,定义在 std 命名空间下)
#include <iostream>
#include <string>
using namespace std;
int main () {
return 0 ;
}
二、string 的基本初始化:多种创建方式
string 提供了多种初始化方式,满足不同场景的需求,以下是最常用的几种:
2.1. 空字符串初始化
创建一个长度为 0 的空字符串,后续可通过赋值、拼接等操作填充内容。
string str1;
string str2 = "" ;
2.2. 直接用字符串常量初始化
最常用的方式,直接将双引号包裹的字符串常量赋值给 string 对象。
string str3 = "Hello, C++ string!" ;
string str4 ("Welcome to C++ world" ) ;
2.3. 用另一个 string 对象初始化
复制已有 string 对象的内容,创建一个新的字符串对象。
string str5 = str3;
string str6 (str4) ;
2.4. 用指定字符和长度初始化 int n = 5 ;
char ch = 'a' ;
string str7 (n, ch) ;
2.5. 截取其他字符串的部分内容初始化 从已有字符串的指定索引开始,截取指定长度的内容(后续 substr 方法会详细讲解)。
string str8 = "Hello, World!" ;
string str9 (str8, 7 , 5 ) ;
三、string 的核心基础操作
3.1. 获取字符串长度 / 判断是否为空 string 提供了两种获取长度的方法,功能完全一致,还有一个专门判断是否为空的高效方法:
size():返回字符串的字符个数(推荐,语义更清晰,与其他 STL 容器保持一致)
length():返回字符串的字符个数(历史遗留方法,与 size() 等价)
empty():判断字符串是否为空,为空返回 true,否则返回 false(比 size() == 0 更高效)
string str = "Hello, C++" ;
cout << "字符串长度(size()):" << str.size () << endl;
cout << "字符串长度(length()):" << str.length () << endl;
if (str.empty ()) {
cout << "str 是空字符串" << endl;
} else {
cout << "str 不是空字符串" << endl;
}
string empty_str;
if (empty_str.empty ()) {
cout << "empty_str 是空字符串" << endl;
}
3.2. 字符串的访问:下标 [] vs at () string 支持两种访问单个字符的方式,均通过索引获取:
(1)下标运算符 []
语法:str[index]
特点:不做越界检查,若索引超出范围(index >= str.size() 或 index < 0),会导致未定义行为 (程序可能崩溃、输出乱码等)
适用场景:确定索引不会越界时(如循环遍历),效率更高
(2)at() 成员方法
语法:str.at(index)
特点:会做越界检查,若索引超出范围,会抛出 std::out_of_range 异常
适用场景:索引可能不确定(如用户输入、动态计算),需要安全校验时
string str = "Hello" ;
cout << "通过 [] 访问第 0 个字符:" << str[0 ] << endl;
cout << "通过 [] 访问第 3 个字符:" << str[3 ] << endl;
cout << "通过 at() 访问第 1 个字符:" << str.at (1 ) << endl;
cout << "通过 at() 访问第 4 个字符:" << str.at (4 ) << endl;
cout << "循环遍历字符串([]):" ;
for (int i = 0 ; i < str.size (); ++i) {
cout << str[i] << " " ;
}
cout << endl;
3.3. 字符串的修改与拼接 string 提供了多种便捷的修改和拼接方式,告别 C 语言的 strcat、strcpy。
(1)直接赋值(覆盖原有内容) 使用 = 运算符,直接将新字符串覆盖原有字符串的内容。
string str = "Old string" ;
cout << "赋值前:" << str << endl;
str = "New string" ;
cout << "赋值后:" << str << endl;
(2)拼接操作(追加内容,不覆盖原有内容)
方式 1:+= 运算符(简洁高效,推荐日常使用),支持拼接 string 对象、字符串常量、单个字符
方式 2:append() 方法(功能更强大,支持拼接部分字符串、多个重复字符等)
string str1 = "Hello" ;
string str2 = " World" ;
str1 += str2;
cout << "拼接后 1:" << str1 << endl;
str1 += "!" ;
cout << "拼接后 2:" << str1 << endl;
str1 += '@' ;
cout << "拼接后 3:" << str1 << endl;
string str3 = "I love" ;
str3. append (" C++" );
cout << "append 拼接后 1:" << str3 << endl;
str3. append (3 , '!' );
cout << "append 拼接后 2:" << str3 << endl;
str3. append (str1, 0 , 5 );
cout << "append 拼接后 3:" << str3 << endl;
3.4. 字符串的比较 string 支持直接使用比较运算符进行字符串比较,也提供了 compare() 方法,比较规则与 C 语言的 strcmp 一致:按字符的 ASCII 码值逐字符比较,直到出现不同字符或到达字符串末尾 。
(1)比较运算符(推荐,简洁直观) 支持的运算符:==(相等)、!=(不相等)、>(大于)、<(小于)、>=(大于等于)、<=(小于等于)
(2)compare() 方法(功能更强大,返回整数值)
返回值:0(两个字符串相等)、正数(当前字符串大于目标字符串)、负数(当前字符串小于目标字符串)
string str1 = "Apple" ;
string str2 = "Banana" ;
string str3 = "Apple" ;
if (str1 == str3) {
cout << "str1 与 str3 相等" << endl;
}
if (str1 < str2) {
cout << "str1 小于 str2" << endl;
}
if (str2 != str1) {
cout << "str2 与 str1 不相等" << endl;
}
int result = str1. compare (str2);
if (result < 0 ) {
cout << "str1.compare(str2) 返回负数,str1 < str2" << endl;
}
result = str1. compare (str3);
if (result == 0 ) {
cout << "str1.compare(str3) 返回 0,str1 == str3" << endl;
}
result = str1. compare (0 , 3 , str2, 0 , 3 );
cout << "str1 前 3 个字符与 str2 前 3 个字符比较结果:" << result << endl;
四、string 的常用实用操作
4.1. 字符串查找:find () find() 方法用于在当前字符串中查找指定的子串或字符,返回首次出现的索引 ;若查找失败,返回 string::npos(一个静态常量,代表无效索引,通常被定义为 -1,但实际是无符号整数类型)。
str.find(substr):查找子串 substr 首次出现的索引
str.find(ch):查找字符 ch 首次出现的索引
str.find(substr, pos):从索引 pos 开始,查找子串 substr 首次出现的索引
string str = "Hello, World! Hello, C++!" ;
string substr = "Hello" ;
char ch = 'W' ;
size_t index1 = str.find (substr);
if (index1 != string::npos) {
cout << "子串 \"" << substr << "\" 首次出现的索引:" << index1 << endl;
}
size_t index2 = str.find (ch);
if (index2 != string::npos) {
cout << "字符 \'" << ch << "\' 首次出现的索引:" << index2 << endl;
}
size_t index3 = str.find (substr, 7 );
if (index3 != string::npos) {
cout << "从索引 7 开始,子串 \"" << substr << "\" 首次出现的索引:" << index3 << endl;
}
size_t index4 = str.find ("Java" );
if (index4 == string::npos) {
cout << "未找到子串 \"Java\"" << endl;
}
注意:find() 的返回值类型是 size_t(无符号整数类型),不要用 int 接收,避免负数转换问题。
4.2. 字符串截取:substr () substr() 方法用于截取字符串的一部分,返回一个新的 string 对象,不会修改原字符串。
str.substr(pos, len):从索引 pos 开始,截取长度为 len 的字符串
若 len 省略,或 pos + len 超出字符串长度,则截取到字符串末尾
string str = "Hello, World! Hello, C++!" ;
string sub1 = str.substr (7 , 5 );
cout << "截取结果 1:" << sub1 << endl;
string sub2 = str.substr (19 );
cout << "截取结果 2:" << sub2 << endl;
4.3. 字符串替换:replace () replace() 方法用于将字符串中的指定部分替换为新的字符串,会修改原字符串 。
str.replace(pos, len, new_str):从索引 pos 开始,将长度为 len 的字符串替换为 new_str
string str = "I love Java!" ;
cout << "替换前:" << str << endl;
str.replace (7 , 4 , "C++" );
cout << "替换后:" << str << endl;
str.replace (7 , 3 , "C++ Programming" );
cout << "再次替换后:" << str << endl;
4.4. 清空字符串:clear () clear() 方法用于清空字符串的所有内容,清空后字符串变为空字符串,size() 返回 0。
string str = "Hello, C++!" ;
cout << "清空前长度:" << str.size () << endl;
str.clear ();
cout << "清空后长度:" << str.size () << endl;
cout << "是否为空:" << (str.empty () ? "是" : "否" ) << endl;
五、string 与 C 语言字符数组的转换 在实际开发中,我们可能需要与 C 语言接口交互(如某些函数要求传入 const char* 类型参数),此时需要进行 string 与 C 语言字符数组的转换。
5.1. string 转 const char*(两种方法)
c_str():返回一个以 \0 结尾的 const char*(C 风格字符串),是最常用的方法
data():C++11 及以后,data() 与 c_str() 功能一致,均返回 const char*;C++11 之前,data() 不保证返回的字符串以 \0 结尾
注意:返回的 const char* 是只读的,不能修改其内容其有效期与原 string 对象一致,若原 string 对象被修改(如赋值、拼接)或销毁,返回的指针将失效
string str = "Hello, C language!" ;
const char * c_str1 = str.c_str ();
cout << "c_str() 转换结果:" << c_str1 << endl;
const char * c_str2 = str.data ();
cout << "data() 转换结果:" << c_str2 << endl;
str = "Modified string" ;
5.2. const char* 转 string 直接赋值即可,非常简洁,string 会自动处理 \0 结尾,无需手动管理长度。
const char * c_str = "Hello, C++ string!" ;
string str = c_str;
cout << "转换后的 string:" << str << endl;
string str2 (c_str) ;
cout << "初始化转换后的 string:" << str2 << endl;
六、完整可运行示例代码 将以上知识点整合为一个完整程序,可直接复制编译运行:
#include <iostream>
#include <string>
using namespace std;
int main () {
string str = "Hello, C++!" ;
string str_copy = str;
string str_char (5 , 'a' ) ;
cout << "原始字符串:" << str << endl;
cout << "拷贝字符串:" << str_copy << endl;
cout << "字符填充字符串:" << str_char << endl;
cout << "字符串长度:" << str.size () << endl;
cout << "是否为空:" << (str.empty () ? "是" : "否" ) << endl;
cout << "第 0 个字符:" << str[0 ] << endl;
str[0 ] = 'h' ;
cout << "修改后字符串:" << str << endl;
str += " Welcome!" ;
cout << "拼接后字符串:" << str << endl;
size_t index = str.find ("Welcome" );
if (index != string::npos) {
string sub = str.substr (index);
cout << "找到的子串:" << sub << endl;
}
str.replace (index, 7 , "Hello World" );
cout << "替换后字符串:" << str << endl;
const char * c_str = str.c_str ();
cout << "C 风格字符串:" << c_str << endl;
str.clear ();
cout << "清空后字符串长度:" << str.size () << endl;
return 0 ;
}
七、模拟实现 string 下面是我根据 string 的主要功能模拟实现的部分 string 的函数,大家可以参考一下
7.1. string.h #define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <assert.h>
using namespace std;
namespace demo {
class string {
public :
typedef char * iterator;
typedef const char * const_iterator;
iterator begin () { return _str; }
iterator end () { return _str + _size; }
const_iterator begin () const { return _str; }
const_iterator end () const { return _str + _size; }
string (const char * str) {
_size = strlen (str);
_capacity = _size;
_str = new char [_capacity + 1 ];
strcpy (_str, str);
}
~string () {
delete [] _str;
_str = nullptr ;
_size = _capacity = 0 ;
}
const char * c_str () const { return _str; }
void clear () { _str[0 ] = '\0' ; _size = 0 ; }
size_t size () { return _size; }
size_t capacity () { return _capacity; }
char & operator [](size_t pos) {
assert (pos < _size);
return *(_str + pos);
}
const char & operator [](size_t pos) const {
assert (pos < _size);
return *(_str + pos);
}
void reserve (size_t n) ;
void push_back (char ch) ;
void append (const char * str) ;
string& operator +=(char ch);
string& operator +=(const char * str);
void insert (size_t pos, char ch) ;
void insert (size_t pos, const char * str) ;
void erase (size_t pos, size_t len = npos) ;
size_t find (char ch, size_t pos = 0 ) ;
size_t find (const char * str, size_t pos = 0 ) ;
string substr (size_t pos = 0 , size_t len = npos) ;
private :
char * _str;
size_t _size;
size_t _capacity;
static const size_t npos;
};
bool operator <(const string& s1, const string& s2);
bool operator <=(const string& s1, const string& s2);
bool operator >(const string& s1, const string& s2);
bool operator >=(const string& s1, const string& s2);
bool operator ==(const string& s1, const string& s2);
bool operator !=(const string& s1, const string& s2);
ostream& operator <<(ostream& out, const string& s);
istream& operator >>(istream& in, string& s);
}
7.2. string.cpp #define _CRT_SECURE_NO_WARNINGS 1
#include "string.h"
using namespace std;
namespace demo {
const size_t string::npos = -1 ;
void string::reserve (size_t n) {
if (n > _capacity) {
char * tmp = new char [n + 1 ];
delete [] _str;
_str = tmp;
_capacity = n;
}
}
void string::push_back (char ch) {
if (_size == _capacity) {
reserve (_capacity == 0 ? 4 : _capacity * 2 );
}
_str[_size] = ch;
_size++;
_str[_size] = '\0' ;
}
string& string::operator +=(char ch) {
push_back (ch);
return *this ;
}
void string::append (const char * str) {
size_t len = strlen (str);
if (_size + len > _capacity) {
reserve (_size + len > _capacity * 2 ? _size + len : _capacity * 2 );
}
strcpy (_str + _size, str);
_size += len;
}
string& string::operator +=(const char * str) {
append (str);
return *this ;
}
void string::insert (size_t pos, char ch) {
assert (pos <= _size);
if (_size == _capacity) {
reserve (_capacity == 0 ? 4 : _capacity * 2 );
}
size_t end = _size + 1 ;
while (end > pos) {
_str[end] = _str[end - 1 ];
--end;
}
_str[pos] = ch;
_size++;
}
void string::insert (size_t pos, const char * str) {
assert (pos <= _size);
size_t len = strlen (str);
if (_size == _capacity) {
reserve (_size + len > _capacity * 2 ? _size + len : _capacity * 2 );
}
size_t end = _size + len;
while (end > pos + len - 1 ) {
_str[end] = _str[end - len];
--end;
}
for (int i = 0 ; i < len; i++) {
_str[pos + i] = str[i];
}
_size += len;
}
void string::erase (size_t pos, size_t len) {
assert (pos < _size);
if (len > _size) {
_str[pos] = '\0' ;
_size = pos;
} else {
for (size_t i = pos + len; i < _size; i++) {
_str[i - len] = _str[i];
}
_size -= len;
}
}
size_t string::find (char ch, size_t pos) {
assert (pos <= _size);
for (size_t i = pos; i < _size; i++) {
if (ch == _str[i]) return i;
}
return npos;
}
size_t string::find (const char * str, size_t pos) {
assert (pos < _size);
const char * ptr = strstr (_str + pos, str);
if (ptr == nullptr ) {
return npos;
} else {
return ptr - _str;
}
}
string string::substr (size_t pos, size_t len) {
assert (pos < _size);
if (len > _size - pos) {
len = _size - pos;
}
string sub;
sub.reserve (len);
for (size_t i = 0 ; i < len; i++) {
sub += _str[pos + i];
}
return sub;
}
bool operator <(const string& s1, const string& s2) {
return strcmp (s1. c_str (), s2. c_str ()) < 0 ;
}
bool operator <=(const string& s1, const string& s2) {
return s1 < s2 || s1 == s2;
}
bool operator >(const string& s1, const string& s2) {
return !(s1 <= s2);
}
bool operator >=(const string& s1, const string& s2) {
return !(s1 < s2);
}
bool operator ==(const string& s1, const string& s2) {
return strcmp (s1. c_str (), s2. c_str ()) == 0 ;
}
bool operator !=(const string& s1, const string& s2) {
return !(s1 == s2);
}
ostream& operator <<(ostream& out, const string& s) {
for (auto ch : s) {
out << ch;
}
return out;
}
istream& operator >>(istream& in, string& s) {
s.clear ();
const int N = 256 ;
char buff[N];
int i = 0 ;
char ch;
ch = in.get ();
while (ch != ' ' && ch != '\n' ) {
buff[i++] = ch;
if (i == N - 1 ) {
buff[i] = '\0' ;
s += buff;
i = 0 ;
}
ch = in.get ();
}
if (i > 0 ) {
buff[i] = '\0' ;
s += buff;
}
return in;
}
}
void TestString1 () {
demo::string s1 ("hello!" ) ;
cout << s1 << endl;
demo::string s2;
cin >> s2;
cout << s2 << endl;
}
int main () {
TestString1 ();
return 0 ;
}
八、总结
string 是 C++ 标准库的字符串类,使用前需包含 <string> 头文件并引用 std 命名空间。
初始化方式灵活,支持空字符串、常量赋值、对象拷贝等多种形式。
基础操作:size()/length() 获取长度、empty() 判断为空、[]/at() 访问字符、+=/append() 拼接、比较运算符进行比较。
实用操作:find() 查找、substr() 截取、replace() 替换、clear() 清空。
与 C 语言字符数组转换:c_str()/data() 转 const char*,直接赋值实现 const char* 转 string。
进阶拓展
string 的内存管理:string 会自动管理内存,动态扩容,也可通过 reserve() 预分配内存,提升效率。
迭代器遍历:string 支持 STL 迭代器,可用于遍历、排序等操作。
与算法库结合:可使用 <algorithm> 中的函数(如 sort()、reverse())操作 string。
宽字符字符串:wstring 用于处理中文、日文等宽字符,用法与 string 基本一致。
掌握 string 的基本用法,能满足绝大多数日常开发的字符串处理需求,后续可深入学习其进阶特性,进一步提升 C++ 字符串处理的效率和灵活性。
相关免费在线工具 加密/解密文本 使用加密算法(如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