当前位置: 首页 > 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()预分配减少碎片高效处理动态增长数据

 

相关文章:

  • 落实政府网站建设网推怎么做
  • 国内环保行业网站开发张家港seo建站
  • 怎么做网站推广世界杯怎么做好网站搜索引擎优化
  • 网页网络优化seo网络推广技术员招聘
  • 漳州建设局网站首页百度seo查询
  • 怎么制作网站主题个人网站推广方法
  • FFMPEG常用函数
  • 应用层协议 HTTP
  • 618风控战升级,瑞数信息“动态安全+AI”利剑出鞘
  • 无人机航电系统之语音通信技术篇
  • elk+filebeat收集springboot项目日志
  • 开疆智能CCLinkIE转ModbusTCP网关连接川崎机器人配置案例
  • 桥头守望者
  • WRF模式与Python融合技术在多领域中的应用及精美绘图;Python助力WRF自动化运行、WRF模式前后处理
  • Android Navigation 架构
  • 从虚拟机角度解释python3相对导入问题(下)
  • 创始人IP打造:知识付费领域破局的核心方法论
  • 服务器安装指南
  • PyEcharts教程(008):PyEchart仪表盘
  • PYTHON从入门到实践2-环境配置与字符串打印用法
  • ffmpeg环境配置
  • RDKit:药物化学和分子数据处理的强大工具库
  • 左神算法之单辅助栈排序算法
  • OGG双活集群,年故障时间=0分钟!
  • OSS安全合规实战:金融行业敏感数据加密+KMS自动轮转策略(满足等保2.0三级要求)
  • 跟着chrome面板优化页面性能