C++ string 类解析

在 C++ 编程中,字符串处理是一项基础且频繁的操作。相较于 C 语言中以'\0'结尾的字符数组,C++ 标准库提供的string类为我们带来了更便捷、更安全的字符串处理方式。本文将从string类的基本概念出发,详细介绍其常用接口及实战技巧,帮助你彻底掌握string类的使用。

一、为什么要学习 string 类?

C 语言中,字符串是以'\0'结尾的字符集合,虽然 C 标准库提供了str系列函数(如strlenstrcpy等),但这些函数存在明显缺陷:

  • 函数与字符串分离,不符合面向对象(OOP)思想;
  • 底层空间需要用户手动管理,容易出现越界访问、内存泄漏等问题。

string类作为 C++ 标准库的重要组成部分,封装了字符串的存储与操作,无需手动管理内存,且提供了丰富的接口,极大提升了字符串处理的效率与安全性。

二、string 类的基本使用

使用string类前,需包含头文件并引入命名空间:

cpp 复制代码
#include <string>
using namespace std;

1. string 对象的构造

string类提供了多种构造方式,满足不同场景的需求:

cpp 复制代码
int main() {
    // 1. 默认构造(空字符串)
    string s1;
    
    // 2. 用C风格字符串初始化
    string s2("hello world");
    
    // 3. 拷贝构造
    string s3(s2);
    
    // 4. 从指定位置开始拷贝(下标6到结尾)
    string s4(s2, 6);  // 结果:world
    
    // 5. 从指定位置开始拷贝指定长度(下标6开始,拷贝3个字符)
    string s5(s2, 6, 3);  // 结果:wor
    
    // 6. 拷贝长度超过剩余字符时,拷贝到结尾
    string s6(s2, 6, 15);  // 结果:world
    
    // 7. 取C风格字符串的前n个字符
    string s7("hello world", 3);  // 结果:hel
    
    // 8. 用n个相同字符初始化
    string s8(5, 'x');  // 结果:xxxxx
    
    return 0;
}

2. 字符串的访问与遍历

(1)通过operator[]访问

operator[]返回指定位置字符的引用,支持读写操作,越界访问会触发断言报错

cpp 复制代码
int main() {
    string s("hello");
    s[0] = 'H';  // 修改第一个字符
    cout << s[1] << endl;  // 输出:e
    return 0;
}

(2)通过at访问

atoperator[]功能类似,但越界访问会抛出异常,更适合需要捕获错误的场景:

cpp 复制代码
try 
{
    string s("hello");
    cout << s.at(10) << endl;  // 越界,抛出out_of_range异常
} 
catch (const out_of_range& e) 
{
    cout << "错误:" << e.what() << endl;
}

(3)迭代器遍历

迭代器是容器的通用访问方式,string提供了 4 种迭代器:

迭代器类型 功能描述
iterator 正向遍历,可读可写
const_iterator 正向遍历,只读
reverse_iterator 反向遍历,可读可写
const_reverse_iterator 反向遍历,只读

示例代码:

cpp 复制代码
string s("hello");

// 正向迭代器(可读可写)
for (string::iterator it = s.begin(); it != s.end(); ++it) {
    *it += 1;  // 每个字符后移一位(h→i, e→f, 等)
}

// 反向迭代器(只读)
const string cs("world");
for (string::const_reverse_iterator rit = cs.rbegin(); rit != cs.rend(); ++rit) {
    cout << *rit << " ";  // 输出:d l r o w
}

(4)范围 for 遍历

C++11 引入的范围 for 可简化遍历,底层基于迭代器实现,适合无需下标时使用

cpp 复制代码
string s("hello");
// 只读遍历
for (char ch : s) {
    cout << ch << " ";
}

// 读写遍历(需加引用)
for (char& ch : s) {
    ch = toupper(ch);  // 转为大写
}

3. 字符串的长度与容量

string类提供了多个接口用于管理长度与容量:

  • size():返回字符串中字符的个数(推荐使用);
  • length():与size()功能相同,仅为兼容历史代码;
  • capacity():返回当前已分配的内存可容纳的最大字符数(不含'\0');
  • max_size():返回字符串可容纳的最大字符数(受系统限制)。

示例:

cpp 复制代码
string s("hello");
cout << s.size() << endl;      // 5
cout << s.capacity() << endl;  // 通常大于等于5(取决于编译器)

4. 字符串的修改与操作

(1)插入操作

insert可在指定位置插入字符或字符串(谨慎使用,频繁头插效率低):

cpp 复制代码
string s("hello");
s.insert(1, "as");  // 在下标1前插入"as" → hasello
s.insert(1, 2, 'c');  // 在下标1前插入2个'c' → hccasello

(2)追加操作

优先使用以下高效的尾插方式:

  • push_back(char c):尾插单个字符;
  • operator+=:追加字符或字符串(推荐);
  • append(const string& str):追加字符串。

示例:

cpp 复制代码
string s("hello");
s.push_back(' ');    // hello 
s += "world";        // hello world
s.append("!");       // hello world!
(3)删除操作

erase可删除指定范围的字符,pop_back()用于尾删:

cpp 复制代码
string s("hello world");
s.erase(5, 1);  // 从下标5开始删除1个字符 → helloorld
s.pop_back();    // 尾删最后一个字符 → helloorl

(4)清空操作

clear()用于清空字符串内容(不释放容量):

cpp 复制代码
string s("hello");
s.clear();
cout << s.size() << endl;      // 0
cout << s.capacity() << endl;  // 仍为原容量(如5)

5. 字符串的查找与替换

(1)查找操作

find系列函数用于查找字符或子串,返回匹配的起始下标,未找到则返回string::npos(一个极大值):

  • find(str, pos):从pos开始正向查找str
  • rfind(str, pos):从pos开始反向查找str
  • find_first_of(str):查找str中任意字符的首次出现位置;
  • find_last_of(str):查找str中任意字符的最后出现位置。

示例:获取文件后缀

cpp 复制代码
string file("test.cpp");
size_t pos = file.rfind('.');  // 反向查找'.',避免文件名含多个'.'
string suffix = file.substr(pos);  // 从pos开始取子串 → .cpp

(2)替换操作

replace(pos, len, str):从pos开始,替换len个字符为str

cpp 复制代码
string s("hello world");
s.replace(5, 1, "%%");  // 下标5开始的1个字符替换为"%%" → hello%%world

高效替换技巧:当需要大量替换时,建议用 "空间换时间",避免频繁修改原字符串:

cpp 复制代码
string s("hello world hello");
string tmp;
for (char ch : s) {
    if (ch == ' ') tmp += "%%";  // 空格替换为"%%"
    else tmp += ch;
}
s.swap(tmp);  // 交换两个字符串(高效,无内存拷贝)

6. 其他常用接口

  • substr(pos, len):获取从pos开始、长度为len的子串(默认取到结尾);
  • c_str():返回 C 风格字符串(const char*),用于兼容 C 语言函数;
  • stoi(str):将字符串转换为整型(类似的还有stolstod等);
  • to_string(val):将其他类型(如 int、double)转换为字符串;
  • getline(cin, str, delim):读取一行字符串,默认以换行符结束,可指定分隔符delim

三、string 类的内存管理

string类会自动管理内存,但合理控制容量可提升效率:

  • reserve(n):提前预留n个字符的空间(不含'\0'),避免频繁扩容;
  • shrink_to_fit():请求将容量缩减至与长度匹配(编译器可能忽略)。

示例:提前预留空间

cpp 复制代码
string s;
s.reserve(100);  // 预留100个字符的空间
for (int i = 0; i < 100; ++i) {
    s.push_back('a');  // 无需扩容,效率更高
}
相关推荐
这周也會开心2 小时前
Java面试题2-集合+数据结构
java·开发语言·数据结构
子枫秋月2 小时前
模拟C++string实现
数据结构·c++·算法
oioihoii2 小时前
C++内存安全方案前沿研究
c++·安全·mfc
十五年专注C++开发2 小时前
QProcess在Windows下不能正常启动exe的原因分析
开发语言·c++·windows·qprocess·createprocess
无限进步_2 小时前
C++多态全面解析:从概念到实现
开发语言·jvm·c++·ide·git·github·visual studio
.似水2 小时前
Python面向对象
开发语言·python
无限进步_2 小时前
C++ STL容器适配器深度解析:stack、queue与priority_queue
开发语言·c++·ide·windows·算法·github·visual studio
山土成旧客2 小时前
【Python学习打卡-Day30】模块化编程:从“单兵作战”到“军团指挥”
开发语言·python·学习
世转神风-2 小时前
qt-union-联合体基础讲解
开发语言·qt