当前位置: 首页 > news >正文

C++ string类的操作

1. 为什么需要string类?

C字符串的缺陷

  • 手动管理内存:易引发越界访问、内存泄漏

  • 不符合OOP思想:数据与操作分离

string类的优势

  • 封装字符序列,自动管理内存

  • 提供丰富的成员方法(如appendfind

  • 无缝集成STL算法(如sortreverse

2. string类接口

2.1 构造与初始化

构造函数作用示例
string()创建空字符串string s1;
string(const char* s)C字符串初始化string s2("hello");
string(const string& str)拷贝构造string s3(s2);
string(size_t n, char c)填充n个字符cstring s4(5, 'x');
string(const char* s, size_t n)取C字符串前n个字符string s5("world", 3);
string(const string& str, size_t pos, size_t len)从str的pos位置取len个字符string s6(s2, 1, 3);
#include<iostream>
#include<string>
#include<list>
#include<algorithm>using namespace std;void test_string()
{//常用string s1;//string()string s2("hello world");//string(const char* s)string s3(s2);//string(const string& str),Constructs a copy of str.//不常用,了解string s4(s2, 3, 5);//string(const string& str, size_t pos, size_t len = npos)string s5(s2, 3);string s6(s2, 3, 30);string s7("hello world", 5);//string(const char* s, size_t n)string s8(10, 'x');//string(size_t n, char c)cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cout << s4 << endl;cout << s5 << endl;cout << s6 << endl;cout << s7 << endl;cout << s8 << endl;}

常用的构造 

  • string s1;//string(),构建一个长度为0的空字符串
  • string s2("hello world");//string(const char* s),//复制指针"hello world"(s)指向地址的字符串,初始化s2
  • string s3(s2);//string(const string& str),Constructs a copy of str.使用字符串s2(str)构造s3

不常用的构造

  • string s4(s2, 3, 5);//string(const string& str, size_t pos, size_t len = npos).从s2(str)的下标为3的位置处(size_t pos)拷贝5个字符长度(size_t len = npos)构造s4(string)
  • string s5(s2, 3);//string(const string& str, size_t pos, size_t len = npos).从s2(str)的下标为3的位置处(size_t pos),拷贝到s2结束
  • string s6(s2, 3, 30);//string(const string& str, size_t pos, size_t len = npos).从s2(str)的下标为3的位置处(size_t pos),拷贝30个字符长度,在这里30个字符已经超出数组长度,只会拷贝到s2结束
  • string s7("hello world", 5);//string(const char* s, size_t n),从"hello world"(s)指针处开始拷贝5个字符(size_t n)
  • string s8(10, 'x');//string(size_t n, char c),拷贝10个"x"初始化s8

构造时可能涉及到隐式类型转换

//隐式类型转换
string s9 = "hello world";
const string& s10 = "hello world";
  • 在string s9 = "hello world";中,"hello world";被构造成一个临时的string对象,再用这个临时的string对象拷贝构造s9,但编译器会优化为“hello world”直接构造s9。
  • 在const string& s10 = "hello world";中,"hello world";构造的临时对象具有常性,不能被修改,所以引用时需要使用const。

2.2 容量操作

方法作用
s.size()返回有效字符长度(同length()
s.capacity()返回总空间大小
s.reserve(size_t n)分配字符串长度最大为n
s.resize(size_t n, char c)调整有效字符数为n,多出的空字符用"c"代替,超出n的删除

 2.3 访问与遍历 

方式语法特点
下标[]s[i]越界触发assert
正向迭代器for(auto it=s.begin(); it!=s.end(); ++it)兼容STL算法
反向迭代器for(auto rit=s.rbegin(); rit!=s.rend(); ++rit)逆序访问
范围forfor(auto& ch : s)操作方便

2.3.1访问

class string
{
public:char& operator[](size_t i){assert(i < _size);//越界检查return _str[i];}
private:char* _str;size_t _size;size_t _capacity;
};
  • char& operator[] (size_t pos);//可修改访问位置上的元素
  • const char& operator[] (size_t pos) const;//不可修改访问位置上的元素
void test_string3()
{string s1("hello world");s1[0] = 'x';// assert(i < _size)会强制检查是否越界//s1[20];const string s2("hello world");// 不能修改//s2[0] = 'x';
}
  • 在s1[0] = 'x';中,s1没有用const修饰,可以修改s1的内容,这时调用char& operator[] (size_t pos);使用[]访问元素,并支持修改。
  • 在s2[0] = 'x';中,s2被const修饰,不可以修改s2的内容,这时调用const char& operator[] (size_t pos) const;,使用[]访问元素,不支持修改。

2.3.2 遍历

//const string s1("hello world");使用const修饰的字符串,支持遍历不支持修改
string s1("hello world");

方式1:下标 + []

//正序遍历
for (size_t i = 0; i < s1.size(); i++)
{s1[i] = s1[i] + 1;cout << s1[i] << " ";//类似遍历数组
}//逆序遍历
for (size_t i = s1.size() - 1; i >= 0; i--)
{cout << s1[i] << " ";//类似遍历数组if(i == 0){break;}
}

遍历方式与数组遍历相似。

使用下标+[ ]遍历、修改元素:其中s1[i] = s1[i] + 1; ,这里将s1的每个元素向后移动一位。

方式2:正迭代器string::iterator和逆迭代器reverse_iterator

string::iterator it1 = s1.begin();
(*(it1 + 1)) = 'o';//使用迭代器修改元素
while(it1 != s1.end())//将it1类似等价于指针来用
{cout << *it1 << " ";it1++;
}//迭代器逆序
string::reverse_iterator it2 = s1.rbegin();
while (it2 != s1.rend())
{cout << *it2 << " ";++it2;
}

迭代器遍历类似指针遍历

  • begin:任何容器返回第一个数据位置的iterator。string::iterator it1 = s1.begin()返回开始位置,类似函数调用返回第一个位置的指针,it1指向s1的h位置=》*(it1)==h,it1++会使it1向尾端移动。
  • end:任何容器返回最后数据的下一个位置iterator。s1.end()返回结束位置下一个位置的迭代器,=》*(end())==\0。
  • rbegin:任何容器返回最后一个数据位置的iterator。string::reverse_iterator it2 = s1.rbegin();返回最后一个数据位置(d的位置)存到it2中,要说明的是it2++会使it2朝着字符串的首字符移动。
  • rend:任何容器返回第一个数据位置的iterator。s1.rend()返回首个元素的位置('h')。

使用迭代器修改元素:(*(it1 + 1)) = 'o';将下标为1的元素修改为'o'

方式3:for+auto

for (auto& e : s1)
{e = 'o';cout << e << " ";
}

遍历方式:自动取s1中的值给e,自动往后++,自动判断结束。

e='o',将s1给e的值修改为'o';

2.4 插入与删除

操作方法关键特性
尾部追加push_back(char c)单字符高效
 append(...)/operator+=支持字符串/子串/填充
任意位置insert(size_t pos, ...)可能触发扩容
 replace(size_t pos, len, ...)可覆盖原字符(len>0时)
删除erase(size_t pos, len)删除[pos, pos+len)区间
 erase(iterator pos)删除迭代器位置字符

2.4.1 插入

string s1("hello world");

方式1:s1.push_back(char c);将字符c插入到字符串s1的末尾,string::push_back - C++ Reference

s1.push_back('x');

 方式2:append,尾插,string::append - C++ Reference

string s2("gogogo");
s1.append(s2);//string& append(const string& str),将string对象s1(str)拷贝到s1尾部
s1.append(s2,1,3);//string& append(const string& str,size_t subpos, size_t sublen),将string对象(str)的第1个位置(subpos)开始拷贝3个字符长度(sublen)到s1的尾部
s1.append(" yyyyyy!!");//string& append(const char* s),s指向以'\0'终止点字符串,将指针s指向字符串拷贝到s1尾部
s1.append(" yyyyyy!!", 3);//string& append(const char* s, size_t n),将指针s指向的字符串前n个字符拷贝到s1尾部
s1.append(3, 'c');//string& append(size_t n, char c),连续追加3个(n个)字符c(char c)到s1的尾部

 方式3:+=,尾插,string::operator+= - C++ Reference

string s2("111111");
s1 += s2;//string& operator += (const string& str),将string对象s2拷贝到s1的尾部
s1 += 'y';//string& operator += (char c),将一个字符'y'(char c)追加到s1尾部
s1 += "zzzzzzzz";//string& operator += (const char* s),s指向以'\0'终止点字符串,将s复制到s1的尾部

 方式4:+,返回一个新构造的字符串对象。operator+ (string) - C++ Reference

string s1 = "hello";
string s2 = "hello11";string ret1 = s1 + s2;//string operator+ (const string& lhs, const string& rhs),在字符s1(lhs)后面串联s2(rhs),构造一个新的字符串ret1.

方式5:insert,任意位置插入,string::insert - C++ Reference

string s2("hello world");
string s1(" happy happy");
s2.insert(s2.size(), s1);//string& insert(size_t pos, const string& str),在s2的s2.size()位置处(pos)插入string对象s1(str)
s2.insert(s2.size(), s1, 3, 2);//string& insert(size_t pos, const string& str, size_t subpos, size_t sublen),string对象s1(str)从下标3(subpos)开始持续2字符长度(sublen),插入到s2的s2.size()位置处(pos),s2.insert(s2.end(), s1.begin(), s1.end());//void insert(iterator p, InputIterator first, InputIterator last),将[first, last)即(s1.begin(), s1.end())范围的字符序列拷贝到s2.end()位置处(p)char ch = 'y';
s2.insert(0, 2, ch);//string& insert(size_t pos, size_t n, char c),将2个(size_t n)ch字符(char c)插入到s2的0位置处(size_t pos)

方式6:replace,任意位置插入(可以覆盖原字符串上的字符,若选择覆盖0字符,与插入效果类似),string::replace - C++ Reference

string s2("hello world");
s2.replace(1, 0, "%20");//string& replace (size_t pos, size_t len, const char* s),"%20"(s)指向的字符串以'\0'解尾,在下标尾1的位置处(pos),插入"%20"(char* s),覆盖s2中的0个字符(len)
s2.replace(1, 0, "happy",2);//string& replace (size_t pos, size_t len, const char* s, size_t n),"happy"(s)指向的字符串以'\0'解尾,在下标尾1的位置处(pos),插入"happy"(char* s)的前2个字符(n),覆盖s2中的0个字符(len)string s1("happy happy");
s2.replace(0, 0, s1);//string& replace (size_t pos, size_t len, const string& str),在s2的0下标(pos)处,插入string对象s1(str),并覆盖s2中的0个字符(len)s2.replace(0, 0, s1, 0, 5);//string& replace (size_t pos, size_t len, const string& str,size_t subpos, size_t sublen),,将string对象s1(str)从下标0(subpos)开始连续5个元素长度(sublen),拷贝到s2的0下标(pos)处,并覆盖s2中的0个字符(len)。s2.replace(0, 0, 3, 'o');//string& replace(size_t pos, size_t len, size_t n, char c),s2的下标0位置处(pos)覆盖0个字符长度(len),插入3个(n)'o'字符(char c)

2.4.2 删除

方式1: erase删除,string::erase - C++ Reference

string s2("hello world");
s2.erase(0, 2);//string& erase (size_t pos = 0, size_t len = nops),从0位置处(pos)连续删除两个字符(npos)s2.erase(s2.begin()+1);//iterator erase (iteror p),在s2.begin()+1位置处(p),删除一个元素s2.erase(s2.begin()+1, s2.end()-1);//iterator erase (iterator first, iterator last),删除[s2.begin()+1, s2.end()-1)之间的元素,左闭右开

 方式2:replace删除

使用replace删除的语法与插入的类似,只不过将插入的字符替换为空,eg:

s2.replace(1, 1, "");//string& replace(size_t pos, size_t len, const char* s),在""为空,使用空,从下标1位置处(pos)开始覆盖3个字符(len)长度。

2.5 改变容量

方法行为示例
reserve(n)扩容:当n > capacity()时重新分配s.reserve(100);
 不缩容n < capacity()时保留空间s.reserve(10); (VS特性)
resize(n, c)n < size():截断多余字符s.resize(5);
 n > size():填充c至长度ns.resize(10, '!');

方式1:reverse,预设字符串长度,提前开好空间。改变capacity,不会改变字符串的实际size

string s1("111111111");
cout << "s1的capacity:" << s1.capacity() << endl;
s1.reserve(100);
cout << "s1的capacity:" << s1.capacity() << endl;s1.reserve(20);//vs编译器下默认不缩容
cout << s1.capacity() << endl;

 方式2:resize,调整字符串长度。

s2.resize(10,'1');//void resize(size_t n, char c),在10个空间中(n)用字符'1'填充(char c)
s2.resize(20);//void resize(size_t n),开辟20个空间

 在resize(size_t n)和resize(size_t n, char c)中,如果n小于当前字符串长度,则删除n之后的所有字符。如果n大于当前字符串长度,在末尾自动插入字符填充长度至n,如果指定了char c,则填充c。

2.6 查找、提取元素

方法作用典型场景
find(char c)返回字符首次出现位置url.find(':')
rfind(char c)返回字符末次出现位置file.rfind('.') (取后缀)
substr(pos, len)提取子串[pos, pos+len)s.substr(0, 5)
string url("https://legacy.cplusplus.com/reference/string/string/find/");
string file("string.cpp.zip");

2.6.1 查找

方式1:find,查找第一次出现匹配项的位置。string::find - C++ Reference

size_t pos1 = url.find(':');//size_t find(char c, size_t pos = 0) const;从下标pos开始,查找并返回第一次出现':'的位置(char c)

方式2:rfind,查找最后一次出现匹配项的位置。string::rfind - C++ Reference

size_t pos = file.rfind('.');//size_t rfind(char c, size_t pos = npos) const.从npos位置(末端查找)查找第一次出现字符'.'(char c)的位置。

2.6.2 提取

方式:substr,提取某段区间的元素.string::substr - C++ Reference

//string substr (size_t pos = 0, size_t len = npos) const
string url1 = url.substr(0, pos1 - 0);//提取url中下标[0,pos1-0]之间的元素
string suffix = file.substr(pos);//提取file中下标[0,pos]之间的元素

 3. 总结

string类通过封装复杂性暴露确定性,在C++中实现了安全性与效率的平衡。

设计目标实现机制价值
内存自治RAII自动管理 + 动态扩容彻底避免内存泄漏/越界
操作安全边界检查 + 异常安全稳定可靠的字符串操作
接口统一迭代器兼容STL + 运算符重载(+[]等)无缝结合标准库算法
性能优化reserve()预分配减少碎片高效处理动态增长数据

 

http://www.lqws.cn/news/505207.html

相关文章:

  • Python与Web3.py库交互实践
  • ref() 与 reactive()
  • Android中Navigation使用介绍
  • 跟着AI学习C#之项目实践Day5
  • 从0开始学习R语言--Day31--概率图模型
  • Blaster - Multiplayer P162-PXX
  • 系统性能优化-4 磁盘
  • 【Bluedroid】蓝牙启动之 bta_dm_enable 流程梳理 源码解析
  • 【AI落地应用实战】Chaterm:重新定义终端操作的AI智能工具
  • C# WinForm跨平台串口通讯实现
  • ffmpeg下载地址
  • 数组题解——移除元素​【LeetCode】
  • Windows驱动开发最新教程笔记2025(一)名词解释
  • Nginx SSL/TLS协议栈中配置深度解析与实践指南-优雅草卓伊凡
  • From Tranformer to Decoder ONLY
  • 云原生周刊:Argo CD v3.1 正式发布
  • PyEcharts教程(009):PyEcharts绘制水球图
  • 【HTTP】取消已发送的请求
  • Leaflet面试题200道
  • C++修炼:智能指针
  • 自然语言处理入门
  • centos7 rpm 包升级openssh至10.0版本
  • 解码成都芯谷金融中心文化科技产业园:文化+科技双轮驱动
  • 枫清科技受邀参加2025数据智能大会
  • 如何通过nvm切换本地node环境详情教程(已装过node.js更改成nvm)
  • Vue3+el-table-v2虚拟表格大数据量多选功能详细教程
  • 字节跳动开源了一款 Deep Research 项目
  • YOLO、VOC、COCO数据集格式
  • C++中的数学计算库Eigen
  • LT8311EX一款适用于笔记本电脑,扩展坞的usb2.0高速运转芯片,成对使用,延伸长度达120米