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

C++初阶-string类3

目录

1.元素访问

1.1string::operator[]

1.2string::at

1.3string::back和string::front

2.修饰符

2.1string::operator+=

2.2string::append

2.3string::push_back

2.4string::assign

2.5string::insert

2.6string::erase

2.7string::replace

2.8string::swap

2.9string::pop_back

3.总结



1.元素访问

C++的string类中有Element access这个分类,翻译过来就是元素访问,元素访问有以下的函数:

1.1string::operator[]

在之前的数组的[]的意思就是访问[]里面的位置的下标位置的元素,在string类中也是一样的,返回的是string对象的pos位置的元素:

#include<iostream>
using namespace std;
#include<string>
//重载运算符[]
int main()
{//第一个函数的用法string s1("hello world");cout << s1[4] << endl;//第二个函数的用法const string s2("happy naodongjie");cout << s2[3] << endl;return 0;
}

运行结果如下:

我们在string类中用这个方法来访问string类中的一个字符。

1.2string::at

这个函数除了有检查是否有越界的问题外,其余的和[]差不多,我们主要是注意它们两个如果有越界的情况时,处理的方式不同就可以了:

#include<iostream>
using namespace std;
#include<string>
//string::at
int main()
{string s1("hello world");cout << s1[100] << endl;//cout << s1.at(100) << endl;return 0;
}

运行结果如下:

若用at的话,如果越界会有什么问题:

#include<iostream>
using namespace std;
#include<string>
//string::at
int main()
{string s1("hello world");//cout << s1[100] << endl;cout << s1.at(100) << endl;return 0;
}

结果如下:

当然,我们是看不懂这个东西的意思的,第一个底层是用assert(pos<size())来判断是否越界的,所以它会直接强制终止程序,相对比较暴力;而第二个底层则是用try{}catch{}这种方式来捕获异常的,相对比较好。要了解它们两个区别需要看一下Deepseek的回答:

所以二者可以交互使用,如果是比较大的程序的时候,我的建议是用at因为它不会直接终止程序,而会去捕获异常。

1.3string::back和string::front

这两个函数可以通过二者的函数名来知道结果,所以在这里暂时只讲解一般用法:

#include<iostream>
using namespace std;
#include<string>
//string::back
//string::front
int main()
{string s1("hello world");cout << s1.front() << endl;cout << s1.back() << endl;const string s2("hello CSDN");cout << s2.front() << endl;cout << s2.back() << endl;return 0;
}

运行结果为:

2.修饰符

string类中的Modifiers分类是修饰符的意思,包含以下函数:

2.1string::operator+=

这个函数的功能如下:

IL是C++11才添加的,所以我们不用管它,这个函数的功能是把一个string对象或字符串或一个字符添加到string对象结尾,所以这就相当于我们的尾插:

#include<iostream>
using namespace std;
#include<string>
//string::operator+=
int main()
{string s("abc");cout << s << endl;//(1)string s1("def");s += s1;cout << s << endl;//(2)s += "ghi";cout << s << endl;//(3)s += 'j';cout << s << endl;return 0;
}

运行结果如下:

这个函数的功能也相似于我们C语言所学的strcat函数,但是strcat函数是从头开始找\0再在\0后面追加,且strcat是不会扩容的,也就是说可能会出现越界的问题。但是这个+=就不一样了,在追加时都会检查一下是否空间足够的问题,之后所学的很多函数也都会检查。

2.2string::append

append也有添加的意思,它有六个重载函数,这里只讲解前5个的意思,最后一个是插入一个从迭代器first到last的区间

(1)string& append(const string& str);

把string对象(str)添加到string对象后面去,并返回被插入对象的引用。

(2)string& append(const string& str,size_t subpos,size_t sublen);

把str的从subpos位置开始的sublen个字符插入到string对象后面去,如果剩余的字符个数小于sublen则把subpos位置后面的字符全部插入到string对象后面去,并返回被插入对象的引用。

(3)string& append(const char* s);

把s字符串插入到string对象后面去,并返回被插入对象的引用。

(4)string& append(const char* s,size_t n);

取s的前n个字符进行插入到string对象后面,并返回被插入对象的引用。

(5)string& append(size_t n,char c);

插入n个c字符到string对象后面,并返回被插入对象的引用。

#include<iostream>
using namespace std;
#include<string>
//string::append
int main()
{string s1("ab");cout << s1 << endl;//(1)string s2("cd");s1.append(s2);cout << s1 << endl;//(2)string s3("def");s1.append(s3, 1, 10);cout << s1 << endl;//(3)s1.append("gh");cout << s1 << endl;//(4)s1.append("ijk", 2);cout << s1 << endl;//(5)s1.append(3, 'k');cout << s1 << endl;//(6)string s4("lmno");s1.append(s4.begin(), s4.end());cout << s1 << endl;return 0;
}

运行结果为:

append函数比+=运算符所做的事更多,但是+=相对于append使用起来更方便,而且可读性更高,所以二者功能车不多,用法也没有太大区别。

2.3string::push_back

这个函数只有一个功能,就是追加一个字符到字符串的末尾,如:

#include<iostream>
using namespace std;
#include<string>
//string::push_back
int main()
{string s("abcd");string s1("abcd");cout << s.append(1, 'e') << endl;//会报错,因为没有返回值,所以不能这样//cout << s1.push_back('e') << endl;//这样才正确s1.push_back('e');cout << s1 << endl;return 0;
}

运行结果如下:

push_back功能和append第五个重载函数的功能差不多,所以这个函数用得地方不多,而且我们发现它还没有返回值,所以不能直接打印,所以这个函数真的用处不大!

2.4string::assign

这个函数有6个重载,这个函数的功能和=重载函数功能一样,都是赋值,只不过它的功能更多一些:

(1)string& assign(const string& str);

把str直接赋值给string对象(this),并返回string对象的拷贝。

(2)string& assign(const string& str,size_t subpos,size_t sublen);

把str从subpos位置开始的sublen个字符赋值给string对象,并返回string对象的拷贝。

(3)string& assign(const char* s);

把s字符串赋值给string对象,并返回string对象的拷贝。

(4)string& assign(const char* s,size_t n);

把s字符串的前n个字符赋值给string对象,并返回string对象的拷贝。

(5)string& assign(size_t n,char c);

把n个c字符赋值给string对象,并返回string对象的拷贝。

(6)

template <class InputIterator>string& assign (InputIterator first, InputIterator last);

把迭代器从first到last位置的字符赋值给string对象,并返回string对象的拷贝。

#include<iostream>
using namespace std;
#include<string>
//string::assign
int main()
{string s("hello");cout << s << endl;//(1)string s1("ber");s.assign(s1);cout << s << endl;//(2)string s2("what can I say");s.assign(s2);cout << s << endl;//(3)s.assign("Just to do");cout << s << endl;//(4)s.assign("Deepseek", 4);cout << s << endl;//(5)s.assign(3, 'a');cout << s << endl;//(6)string s3("Happy NaoDongJie");s.assign(s3.begin(), s3.end());cout << s << endl;return 0;
}

运行结果为:

assign是否会扩容这种问题需要看是否有出现原空间不够的情况,这个扩容的知识我后面会专门来讲解的。如果原空间不够则需要扩容,否则不扩容。若扩容,则是深拷贝,并需要新申请一块空间;若不扩容则会先clear原空间后再覆盖原内容,这个讲底层的时候会进行更详细的讲解的!

2.5string::insert

insert函数的普遍功能是从pos位置开始插入数据。这些重载函数的解释和前两个差不多(参数名字都一样),所以我就不做解释了,而iterator是迭代器的意思,示例就在deepseek里面生成了,因为这个东西用法确实也不多,我在这里直接用Deepseek的搜索结果了:

在C++中,`std::string`的`insert()`函数有多种重载形式,用于在不同位置插入字符、字符串或子串。以下是所有重载形式的示例:

(1) 在指定位置插入一个字符

std::string s = "Hello";
s.insert(2, 1, 'X');  // 在索引2处插入1个'X'
// 结果: "HeXllo"

(2)在指定位置插入一个C风格字符串

std::string s = "Hello";
s.insert(3, " World");  // 在索引3处插入" World"
// 结果: "Hel Worldlo"

(3) 在指定位置插入另一个`std::string`

std::string s = "Hello";
std::string t = "C++";
s.insert(1, t);  // 在索引1处插入t
// 结果: "HC++ello"

(4) 在指定位置插入另一个`std::string`的子串

std::string s = "Hello";
std::string t = "12345";
s.insert(4, t, 1, 3);  // 在s的索引4处,插入t从索引1开始的3个字符
// 结果: "Hell234o"

(5) 在指定位置插入多个相同字符

std::string s = "Hello";
s.insert(0, 3, '!');  // 在开头插入3个'!'
// 结果: "!!!Hello"

(6) 在迭代器位置插入一个字符

std::string s = "Hello";
s.insert(s.begin() + 1, 'X');  // 在迭代器位置插入'X'
// 结果: "HXello"

(7) 在迭代器位置插入多个相同字符

std::string s = "Hello";
s.insert(s.begin() + 2, 2, 'Y');  // 在索引2处插入2个'Y'
// 结果: "HeYYllo"

(8)在迭代器位置插入一个字符范围(通过迭代器)

std::string s = "Hello";
std::vector<char> vec = {'A', 'B', 'C'};
s.insert(s.begin() + 3, vec.begin(), vec.end());  // 在索引3处插入vec的内容
// 结果: "HelABClo"

(9) 使用初始化列表插入多个字符

std::string s = "Hello";
s.insert(1, {'X', 'Y', 'Z'});  // 在索引1处插入初始化列表
// 结果: "HXYZello"

(10) 在迭代器位置插入初始化列表

std::string s = "Hello";
s.insert(s.begin() + 2, {'X', 'Y'});  // 在索引2处插入初始化列表
// 结果: "HeXYllo"

注意事项
1. 索引越界:如果`pos > size()`,会抛出`std::out_of_range`异常(与`at()`行为一致)。
2. 性能:频繁插入可能导致内存重新分配(扩容),可用`reserve()`预分配空间优化。
3. 返回值:部分重载(如迭代器版本)会返回指向插入内容的迭代器。

如果需要进一步优化或处理边界条件,可以结合`reserve()`和迭代器操作。

此外,insert也要少使用,因为insert需要找这个位置,还要移动后面的数据,所以非常麻烦,效率低。

2.6string::erase

erase有擦除的意思,有三个重载函数:

(1)string& erase(size_t pos=0,size_t len=npos);

从pos位置开始删除len个字符,如果没有给pos,则自动从开始位置开始删除;如果不给len就会删除npos个数据(全部删除)。

(2)iterator erase(iterator p);

可以删除一个迭代器位置,一般用得不多,但是一般用作头删。

(3)iterator erase(iterator first,iterator last);

删除迭代器的一段区间,但一般用前两个就可以实现了。

#include<iostream>
using namespace std;
#include<string>
//string::erase
int main()
{string s1("hello");string s2("hello");string s3("hello");cout << s1 << endl;//(1)s1.erase(1);cout << s1 << endl;//(2)s2.erase(s2.begin());cout << s2 << endl;//(3)s3.erase(s3.begin() + 1, s3.end());cout << s3 << endl;return 0;
}

运行结果为:

2.7string::replace

replace翻译过来有替换的意思。

(1)将str的从pos位置开始的len个字符替换成string对象,或者将str的i1开始的迭代器到i2结束的迭代器替换为string对象;

(2)用str的从subpos位置开始的sublen个字符替换掉string(原字符串)的从pos位置开始的len个字符。

(3)将string对象的从pos位置开始的len个字符替换为s和将原字符串中由迭代器范围[i1, i2)指定的子串,替换为C风格字符串s的内容。

(4)将string对象的从pos位置开始的len他字符替换为s的前n个字符和原字符串中由迭代器范围[i1, i2)指定的子串,替换为C风格字符串s的前n个字符。

(5)将string对象的从pos位置开始的len他字符替换为n个c字符和原字符串中由迭代器范围[i1, i2)指定的子串,替换为C风格字符串s的n个c字符。

这个函数比较复杂,所以我简单讲解一下示例:

#include<iostream>
using namespace std;
#include<string>
//string::replace
int main()
{string s("abcdefg");cout << s << endl;//(1.1)string s1("hijkmln");s.replace(0, 4, s1);cout << s << endl;//(1.2)string s2("hello");s.replace(s.begin(), s.end() - 3, s2);cout << s << endl;//(2)string s3("Just to do");s.replace(1, 5, s3, 0, 4);cout << s << endl;//(3.1)s.replace(0, 3, "abcde");cout << s << endl;//(3.2)s.replace(s.begin() + 1, s.end() - 2, "fghi");cout << s << endl;//(4.1)s.replace(2, 4, "jklmno", 4);cout << s << endl;//(4.2)s.replace(s.begin() + 1, s.end(), "nopq", 2);cout << s << endl;//(5.1)s.replace(0, 2, 2, 'a');cout << s << endl;//(5.2)s.replace(s.begin() + 2, s.end(), 3, 'b');cout << s << endl;return 0;
}

运行结果如下:

这个示例是随便给的,因为是演示一下用法,所以结果是不重要的,主要是熟悉一下迭代器的用法,之后会用迭代器用得多的地方是vector而不是string。

谨慎使用replace,因为大多数情况下效率极低,因为若替换的内容比被替换内容少或者多,都要往前/后移动数据,这种挪动要覆盖内容,影响效率,之后会讲其他的函数如find,如果加上insert等函数也可以实现该功能。

2.8string::swap

顾名思义,这个函数是交换两个string对象,不做过多讲解:

#include<iostream>
using namespace std;
#include<string>
//string::swap
int main()
{string s1("abcdefg");string s2("hijklmnop");s1.swap(s2);cout << s1 << endl;cout << s2 << endl;return 0;
}

运行结果如下:

2.9string::pop_back

这个函数只是删除一个字符的作用,所以用处不大,就不演示用法了。

3.总结

这一讲内容比较多,主要是我把一些不是很重要的函数讲的比较多了一些,而在这篇博客中有一些函数是与其他函数功能类似,有些函数功能也不是很大,所以我们主要是知道+=、[]、erase、swap这些函数的用法,其余的用处不是很大。下讲将讲解以下函数:

这些函数基本上只要知道用法就可以了。喜欢的可以一键三连哦!下讲再见!

相关文章:

  • 日期有关的算法题(ctime库的使用)
  • 盐化行业数字化转型规划详细方案(124页PPT)(文末有下载方式)
  • 网络通信问题及解决方案
  • 用Python代码绘制跳动的梦幻爱心,感受编程的浪漫与奇妙
  • 图与网络模型
  • 人工智能-深度学习之卷积神经网络
  • 如何在Cursor中使用MCP服务
  • 使用Python和Pandas实现的Amazon Redshift权限检查与SQL生成用于IT审计
  • Java SE(6)——类和对象
  • 贪心算法精解(Java实现):从理论到实战
  • python-MySQL鏈接
  • JavaScript延迟加载
  • 【深度学习-Day 2】图解线性代数:从标量到张量,理解深度学习的数据表示与运算
  • OpenStack Yoga版安装笔记(25)Nova Cell理解
  • 【ESP32】st7735s + LVGL使用-------图片显示
  • 【五一培训】Day1
  • MySQL基础关键_003_DQL(二)
  • WEB UI自动化测试之Selenium框架学习
  • 【HarmonyOS】作业三 UI
  • 【信息系统项目管理师-论文真题】2024上半年(第二批)论文详解(包括解题思路和写作要点)
  • 辽宁男篮被横扫这一晚,中国篮球的一个时代落幕了
  • 山西太原一小区发生爆炸,造成1人遇难21人受伤2人失联
  • 国台办:提醒相关人员不要假借去第三地名义绕道赴台
  • 解放日报:中国大模型企业的发展机遇已经到来
  • 中国防疫队深入缅甸安置点开展灾后卫生防疫工作
  • 游客曝九寨沟打网约车被出租车围堵,景区回应:当地无合规网约车