C++ string 标准库核心用法详解
在 C 语言中,我们处理字符串依赖于字符数组和一系列 C 标准库函数(如 strcpy、strcat、strcmp),不仅需要手动管理内存,还容易出现缓冲区溢出等问题。而 C++ 标准库提供的 std::string(简称 ),封装了字符串的所有操作,提供了安全、便捷、高效的字符串处理方案,是 C++ 开发中处理字符串的首选。
C++ string 标准库封装了字符串操作,提供安全高效的解决方案。文章涵盖初始化方式、基础操作(长度、访问、修改、比较)、实用功能(查找、截取、替换、清空)及与 C 风格字符串转换。结合示例代码演示 API 用法,并包含模拟实现部分供进阶参考。

在 C 语言中,我们处理字符串依赖于字符数组和一系列 C 标准库函数(如 strcpy、strcat、strcmp),不仅需要手动管理内存,还容易出现缓冲区溢出等问题。而 C++ 标准库提供的 std::string(简称 ),封装了字符串的所有操作,提供了安全、便捷、高效的字符串处理方案,是 C++ 开发中处理字符串的首选。
string本文将从基础到实用,全面讲解 string 的核心用法,适合 C++ 初学者快速上手,也可作为日常开发的参考手册。
要使用 string,必须满足两个基本条件(缺一不可):
string 头文件(注意无后缀 .h)std 命名空间(string 是标准库中的类,定义在 std 命名空间下)#include <iostream>
#include <string>
using namespace std;
int main() {
// 后续 string 操作写在这里
return 0;
}
string 提供了多种初始化方式,满足不同场景的需求,以下是最常用的几种:
创建一个长度为 0 的空字符串,后续可通过赋值、拼接等操作填充内容。
// 两种等价写法
string str1; // 默认构造函数,空字符串
string str2 = ""; // 赋值空字符串常量
最常用的方式,直接将双引号包裹的字符串常量赋值给 string 对象。
string str3 = "Hello, C++ string!"; // 拷贝初始化
string str4("Welcome to C++ world"); // 直接初始化(构造函数传参)
复制已有 string 对象的内容,创建一个新的字符串对象。
string str5 = str3; // 拷贝初始化,str5 与 str3 内容完全一致
string str6(str4); // 直接初始化,str6 与 str4 内容完全一致
创建一个由 n 个相同字符组成的字符串。
int n = 5;
char ch = 'a';
string str7(n, ch); // str7 = "aaaaa"
从已有字符串的指定索引开始,截取指定长度的内容(后续 substr 方法会详细讲解)。
string str8 = "Hello, World!";
string str9(str8, 7, 5); // 从索引 7 开始,截取 5 个字符,str9 = "World"
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;
}
string 支持两种访问单个字符的方式,均通过索引获取:
[]str[index]index >= str.size() 或 index < 0),会导致未定义行为(程序可能崩溃、输出乱码等)at() 成员方法str.at(index)std::out_of_range 异常示例代码:
string str = "Hello";
// 1. 下标 [] 访问
cout << "通过 [] 访问第 0 个字符:" << str[0] << endl;
cout << "通过 [] 访问第 3 个字符:" << str[3] << endl;
// 2. at() 方法访问
cout << "通过 at() 访问第 1 个字符:" << str.at(1) << endl;
cout << "通过 at() 访问第 4 个字符:" << str.at(4) << endl;
// 3. 循环遍历所有字符(两种方式均可)
cout << "循环遍历字符串([]):";
for (int i = 0; i < str.size(); ++i) {
cout << str[i] << " ";
}
cout << endl;
// 4. 越界访问演示(注释掉,避免程序崩溃)
// str[10]; // 未定义行为,可能崩溃
// str.at(10); // 抛出 out_of_range 异常
string 提供了多种便捷的修改和拼接方式,告别 C 语言的 strcat、strcpy。
使用 = 运算符,直接将新字符串覆盖原有字符串的内容。
string str = "Old string";
cout << "赋值前:" << str << endl;
str = "New string"; // 直接赋值,覆盖原有内容
cout << "赋值后:" << str << endl;
+= 运算符(简洁高效,推荐日常使用),支持拼接 string 对象、字符串常量、单个字符append() 方法(功能更强大,支持拼接部分字符串、多个重复字符等)示例代码:
string str1 = "Hello";
string str2 = " World";
// 1. += 运算符拼接
str1 += str2; // 拼接 string 对象
cout << "拼接后 1:" << str1 << endl;
str1 += "!"; // 拼接字符串常量
cout << "拼接后 2:" << str1 << endl;
str1 += '@'; // 拼接单个字符
cout << "拼接后 3:" << str1 << endl;
// 2. append() 方法拼接
string str3 = "I love";
str3.append(" C++"); // 拼接字符串常量
cout << "append 拼接后 1:" << str3 << endl;
str3.append(3, '!'); // 拼接 3 个重复字符
cout << "append 拼接后 2:" << str3 << endl;
str3.append(str1, 0, 5); // 拼接 str1 的前 5 个字符(从索引 0 开始,长度 5)
cout << "append 拼接后 3:" << str3 << endl;
string 支持直接使用比较运算符进行字符串比较,也提供了 compare() 方法,比较规则与 C 语言的 strcmp 一致:按字符的 ASCII 码值逐字符比较,直到出现不同字符或到达字符串末尾。
支持的运算符:==(相等)、!=(不相等)、>(大于)、<(小于)、>=(大于等于)、<=(小于等于)
compare() 方法(功能更强大,返回整数值)示例代码:
string str1 = "Apple";
string str2 = "Banana";
string str3 = "Apple";
// 1. 比较运算符
if (str1 == str3) {
cout << "str1 与 str3 相等" << endl;
}
if (str1 < str2) {
cout << "str1 小于 str2" << endl;
}
if (str2 != str1) {
cout << "str2 与 str1 不相等" << endl;
}
// 2. compare() 方法
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;
}
// 比较部分字符串(str1 从索引 0 开始,长度 3 与 str2 从索引 0 开始,长度 3 比较)
result = str1.compare(0, 3, str2, 0, 3);
cout << "str1 前 3 个字符与 str2 前 3 个字符比较结果:" << result << endl;
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';
// 1. 查找子串首次出现的索引
size_t index1 = str.find(substr);
if (index1 != string::npos) {
cout << "子串 \"" << substr << "\" 首次出现的索引:" << index1 << endl;
}
// 2. 查找字符首次出现的索引
size_t index2 = str.find(ch);
if (index2 != string::npos) {
cout << "字符 \'" << ch << "\' 首次出现的索引:" << index2 << endl;
}
// 3. 从指定索引开始查找子串
size_t index3 = str.find(substr, 7);
if (index3 != string::npos) {
cout << "从索引 7 开始,子串 \"" << substr << "\" 首次出现的索引:" << index3 << endl;
}
// 4. 查找不存在的子串
size_t index4 = str.find("Java");
if (index4 == string::npos) {
cout << "未找到子串 \"Java\"" << endl;
}
注意:
find()的返回值类型是size_t(无符号整数类型),不要用int接收,避免负数转换问题。
substr() 方法用于截取字符串的一部分,返回一个新的 string 对象,不会修改原字符串。
语法:
str.substr(pos, len):从索引 pos 开始,截取长度为 len 的字符串len 省略,或 pos + len 超出字符串长度,则截取到字符串末尾示例代码:
string str = "Hello, World! Hello, C++!";
// 1. 截取指定长度的字符串
string sub1 = str.substr(7, 5); // 从索引 7 开始,截取 5 个字符
cout << "截取结果 1:" << sub1 << endl;
// 2. 截取到字符串末尾
string sub2 = str.substr(19); // 从索引 19 开始,截取到末尾
cout << "截取结果 2:" << sub2 << endl;
// 3. 索引超出范围(抛出 out_of_range 异常)
// string sub3 = str.substr(100);
replace() 方法用于将字符串中的指定部分替换为新的字符串,会修改原字符串。
语法(常用):
str.replace(pos, len, new_str):从索引 pos 开始,将长度为 len 的字符串替换为 new_str示例代码:
string str = "I love Java!";
cout << "替换前:" << str << endl;
// 将从索引 7 开始的 4 个字符("Java")替换为"C++"
str.replace(7, 4, "C++");
cout << "替换后:" << str << endl;
// 替换为更长的字符串
str.replace(7, 3, "C++ Programming");
cout << "再次替换后:" << str << endl;
clear() 方法用于清空字符串的所有内容,清空后字符串变为空字符串,size() 返回 0。
示例代码:
string str = "Hello, C++!";
cout << "清空前长度:" << str.size() << endl;
str.clear();
cout << "清空后长度:" << str.size() << endl;
cout << "是否为空:" << (str.empty() ? "是" : "否") << endl;
在实际开发中,我们可能需要与 C 语言接口交互(如某些函数要求传入 const char* 类型参数),此时需要进行 string 与 C 语言字符数组的转换。
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!";
// 1. c_str() 转换
const char* c_str1 = str.c_str();
cout << "c_str() 转换结果:" << c_str1 << endl;
// 2. data() 转换
const char* c_str2 = str.data();
cout << "data() 转换结果:" << c_str2 << endl;
// 3. 注意:修改原字符串后,指针失效
str = "Modified string";
// cout << c_str1 << endl; // 未定义行为,输出结果不可预期
直接赋值即可,非常简洁,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() {
// 1. 初始化
string str = "Hello, C++!";
string str_copy = str;
string str_char(5, 'a');
// 2. 输出基本信息
cout << "原始字符串:" << str << endl;
cout << "拷贝字符串:" << str_copy << endl;
cout << "字符填充字符串:" << str_char << endl;
cout << "字符串长度:" << str.size() << endl;
cout << "是否为空:" << (str.empty() ? "是" : "否") << endl;
// 3. 访问与修改
cout << "第 0 个字符:" << str[0] << endl;
str[0] = 'h'; // 小写化第一个字符
cout << "修改后字符串:" << str << endl;
// 4. 拼接
str += " Welcome!";
cout << "拼接后字符串:" << str << endl;
// 5. 查找与截取
size_t index = str.find("Welcome");
if (index != string::npos) {
string sub = str.substr(index);
cout << "找到的子串:" << sub << endl;
}
// 6. 替换
str.replace(index, 7, "Hello World");
cout << "替换后字符串:" << str << endl;
// 7. 转换为 C 风格字符串
const char* c_str = str.c_str();
cout << "C 风格字符串:" << c_str << endl;
// 8. 清空
str.clear();
cout << "清空后字符串长度:" << str.size() << endl;
return 0;
}
下面是我根据 string 的主要功能模拟实现的部分 string 的函数,大家可以参考一下
#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) {
// 检查 pos 合法性
assert(pos < _size);
return *(_str + pos);
}
const char& operator[](size_t pos) const {
// 检查 pos 合法性
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; // string 指针
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);
}
#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);
// len 大于剩余字符长度,更新一下 len
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_str()/data() 转 const char*,直接赋值实现 const char* 转 string。string 的内存管理:string 会自动管理内存,动态扩容,也可通过 reserve() 预分配内存,提升效率。string 支持 STL 迭代器,可用于遍历、排序等操作。<algorithm> 中的函数(如 sort()、reverse())操作 string。wstring 用于处理中文、日文等宽字符,用法与 string 基本一致。掌握 string 的基本用法,能满足绝大多数日常开发的字符串处理需求,后续可深入学习其进阶特性,进一步提升 C++ 字符串处理的效率和灵活性。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online