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

【C++详解】string各种接口如何使用保姆级攻略

文章目录

  • 一、string介绍
  • 二、string使用
    • 构造函数
    • 析构函数
    • 赋值运算符重载
    • string的遍历+修改方法
      • 1、下标+[]
      • 2、迭代器
      • 3、范围for
    • 迭代器使用详解
      • const迭代器
      • 反向迭代器(reverse)
    • Capacity(容量相关)
      • size/length
      • max_size
      • capacity
      • clear/empty
      • shrink_to_fit(缩容)
      • reserve(扩容)
      • resize
    • element access(数据访问)
      • operator[]/at
      • back/front
    • Modifiers(修改相关)
      • append(追加)/operator+=
      • assign(赋值)
      • insert/erase
      • repalce
    • String operations
      • c_str/data
      • copy
      • substr
      • find/rfind
      • find_first_of/find_last_of
    • 非成员函数
      • 关系运算符
      • operator+
      • getline
  • 三、总结


一、string介绍

在学习string之前我们要先了解string其实诞生的比STL早,所以从发展历史角度来看你它应该归于标准库,但是从广义来看它又应归于STL,因为它也是数据结构,它也有STL的各种通用接口。

在这里插入图片描述

从这里我们可以看到我们要学习的string是属于C++标准库的类,并且是经过类模板实例化的具体类型,本质上可以看作的管理char字符的顺序表,也可以简单理解成字符串。
注意:要使用string需要using namespace std和包string头文件。

二、string使用

构造函数

在这里插入图片描述

string的构造函数很多,这里我们介绍最常见的几种。
1、默认构造 string()

	string s1;

2、用常量字符串构造string(const char* s)

	string s2("good moring");

3、拷贝构造 string(const string& str)

	string s3(s2);

4、子串构造 string(const string& str, size_t pos, size_t length = npos)

它的功能是用string的一部分用来拷贝构造,该部分是从pos这个位置到length位置,其中length给了一个缺省参数npos(缺省参数只能用常量,全局变量或者静态变量),它是string的静态成员变量,它的值是整型的最大值,因为string一般不会有这么长,所以用这个值就是为了让string有多少拷贝多少,直到结尾。

	string s4(s3, 1, 7);

5、拷贝前n个字符构造 string(const char* str, size_t n)

	const char* str = "hello world";string s5(str, 7);

6、用n个c字符构造 string(size_t n, char c)

	string s6(100, 'x');

析构函数

在这里插入图片描述

因为string没有动态开辟空间的成员变量,所以就不需要回收资源,调用它的默认析构函数就好了,所以析构我们就不展开讨论了。

赋值运算符重载

在这里插入图片描述

	string s1("good moring");string s2;s2 = s1;s2 = "wusaqi";s2 = 'x';

string的遍历+修改方法

平时我们使用string这个类,遍历和修改操作是不可避免的,接下来小编会介绍三种方法来实现。

1、下标+[]

在这里插入图片描述

我们首先来认识一下string里的operator[]函数,它可以返回string的第pos位置的字符,如果越界了还会报错,并且返回的是引用,代表返回后你还可以修改它。
我们首先可以看到它重载了两个函数,一个参数(也就是this指针)没被const修饰,返回值为char&,一个参数被const修饰,返回值为const char&,但是我们一般只用实现const版本的就行了,因为普通对象也可以调用const,可这里为什么要实现两种呢?因为这样可以让对象使用到最匹配它的函数,因为编译器会去找最匹配对象的函数,不然普通对象去调用后返回的对象就变成不能修改了,违背了我们本意。

	string s1("good morning");for (int i = 0; i < s1.size(); i++){s1[i]++;}cout << s1 << endl;

这样我们就能遍历和修改这个string了,让每一个字符+1。 这里的size接口能返回string的字符个数,但是我们看c++网站就会发现还有一个和size一样功能的接口length,这里其实就涉及到我们之前谈到的历史发展的原因,在STL还没出现的时候string用的就是length,但是当后面STL归进来后为了统一接口才又引入的size。

2、迭代器

在STL容器中都会有迭代器(iterator),它是类型属于这个容器的类型的类域,迭代有遍历的意思,迭代器的用法和指针很相似,可以先把它简单想象成像指针一样的类型对象。
我们要得到迭代器就需要2个成员函数:begin() 和 end(),begin() 返回第一个数据位置的迭代器,end() 返回最后一个数据下一个位置的迭代器,所以可以得到这两个成员函数返回的迭代器的区间是左闭右开的。
用法如下:

	string::iterator it1 = s1.begin();while (it1 != s1.end()){//改变迭代器所在位置的值(*it1)--;//让迭代器向前移动it1++;}

迭代器的意义:
1、同一类似的方式遍历修改容器。
2、算法脱离具体底层结构,和底层结构解耦,算法独立模板实现针对多个容器处理。

3、范围for

在学习范围for之前我们要先了解一些C++11的新特性:
1、auto是关键字,可以自动推导对象的类型,它和具体类型一样,不加&是拷贝,加&才是引用。当auto推导指针时,可以用 auto 也可以用 auto* ,只不过前者可以推导任意类型,后者只能推导指针。

	auto x = 8;auto y = 8.8;cout << x << endl;cout << y << endl;int& z = x;auto m = z;   //拷贝auto& n = z;  //引用auto p = &x;auto* p = &x; //只能推导指针

范围for也是C++11支持的新特性,所有容器都支持,它的用法如下:

	string s1("hello world");for (auto ch : s1){cout << ch << " ";}

上面这段代码做了什么?简而言之就是3个自动:
自动取容器数据赋值给ch(ch位置的名称可以随意取)
自动判断结束
自动迭代(向后遍历)

1、但是范围for无法修改容器里的数据,因为它的底层本质还是会替换成迭代器,就是把*迭代器赋值传递给ch,所以改变ch对容器里的数据没有影响,如果想改变容器里数据就要在zuto后边加&,成为引用。

	string s1("hello world");for (auto& ch : s1){cout << ch << " ";}

2、范围for里面的auto也可以写成具体类型,但是一定要和容器的数据类型匹配。

	string s1("hello world");for (int ch : s1){ch++;}

3、范围for不仅支持容器,数组也支持。

	int arr[] = { 1,2,3,4,5 };for (auto ch : arr){cout << ch << " ";}

迭代器使用详解

先前我们简单了解了一下迭代器,接下来小编详细介绍一下string中各种迭代器和它们的用法。

const迭代器

在这里插入图片描述
在这里插入图片描述

我们看上图可以发现begin()和end()都有两个重载函数,一个普通版,一个const版,当对象没被const修饰时调用普通版,当对象被const修饰时则调用const版,这里我们要注意其中const版本不是const iterator,而是const_iterator,因为如果是前者的话const是修饰迭代器本身无法改变,但是迭代器遍历会一直改变,实践中没法使用,后者才是修改迭代器指向的内容无法改变,这里可以把const_iterator简单理解成一种类型。

	string s1("hello world");string::iterator it1 = s1.begin();const string s2("hello world");string::const_iterator it2 = s1.begin();

反向迭代器(reverse)

在这里插入图片描述
在这里插入图片描述

获取反向迭代器的函数也有两种重载,也是一种普通版,一种const版,这里注意,因为是反向迭代器,所以它是从后向前遍历的,所以rbegin()返回的是最后一个字符的位置,rend()返回的是第一个字符的前一个位置,迭代器++也是从后往前走的。

在这里插入图片描述

迭代器在STL容器中的意义(用法):
1、遍历和修改容器数据。
2、可以把容器数据以迭代器发方式传给算法,因为算法一般是按函数模板传迭代器区间的方式,用迭代器访问容器数据就可以实现算法和容器的底层解耦。

这里还要补充一点,cbegin()和cend()是返回确定的const对象,但是实践中很少这样用,了解一下就行。

Capacity(容量相关)

在这里插入图片描述

在了解容量相关接口之前我们先认识一下string包含哪些内容,具体等我们后面讲到底层实现时小编再仔细讲解,这里我们先大致了解一下:其中有有动态开辟的字符数组_str,字符数组中的有效数据个数_size,还有数组容量_capacity,这里的我们要介绍的接口就是围绕它来展开。

size/length

在这里插入图片描述

它们都是返回字符个数的接口,前面我们详细介绍过,这里小编就不赘述了。

max_size

这其实是一个没有参考意义的接口,了解一下就行,它返回的是理想情况下size最大能有多大,也就是string最长能有多长。

capacity

在这里插入图片描述

我们在使用string过程中难免会插入数据,但是它的容量是动态开辟的,如果你插入一次扩容一次效率就会变得很低,所以引入capacity就是为了解决这一问题,要扩容就会在当前容量的基础上2倍或1.5倍扩容。

在这里插入图片描述

1、这里我们还要注意size和capacity的返回值规定均不包含 \0,所以这里size显示是11,但是实际上是12,还要包含\0,capacity能存15个有效字符,所以实际要开16个字符空间。
2、扩容机制C++并没有统一规定,所以具体实现都由编译器厂商实现,比如vs是第一次二倍扩容,后续是1.5倍,而linux(g++)则是二倍扩容。

clear/empty

clear和empty很简单,这里就一起讲了。

在这里插入图片描述
在这里插入图片描述

clear是将string中所有数据清空,但是capacity不会改变,可以理解成我们在单链表时的size–。

empty就是string对象判空,若当前对象为空,则返回1,若不为空则返回0。

在这里插入图片描述

shrink_to_fit(缩容)

在这里插入图片描述

  • 文档中说明该接口是把空间减少到可以适配size,就是把多余的空间都释放了,但是我们看文档下面:这个请求是no-binding(不具有约束力的),所以编译器可能由于内存对齐之类的原因最后实现出来capacity是大于size的,也就是并没有把多余的空间全部释放。
  • C++规定动态申请的连续的数组空间只支持完整的申请和释放,不能部分释放,所以缩容代价是很大的,它不支持原地缩容,我们想缩容只能重新申请一块空间,再把数据拷贝过来,再释放旧空间。
  • 所以缩容可以理解成是以时间换空间,在如今来看,我们普遍都会采用以空间换时间,现代设备内存普遍都比较大,时间在我们看来会更重要。

reserve(扩容)

在这里插入图片描述

  • 我们看文档可以发现扩容也不是完完全全按照你给的n值来扩容的,假设你要扩到100,最后是可能比100还大的。
  • 当n比capacity小时,我们会期望它能缩容,但是读文档它对缩容是不具有约束力的,也就是缩与不缩是取决于编译器,所以我们要缩容最好使用shrink_ti_fit,但是缩容我们都是不建议用的。
  • reverse是不会影响字符串内容和长度的。
  • 扩容是我们常用的接口,因为当我们确定知道需要多少空间时,可以用它提前开好,避免 多次扩容,提高效率。

resize

在这里插入图片描述

这是改变字符串长度的接口,我们看到它重载了两个函数,当n比size大时,它会插入字符直到符合我们想要的长度,如果没有指定字符,默认会插入 ‘\0’,如果指定了字符,就会插入我们指定的字符。

改变字符串长度有三种情况,让小编来举例介绍:
1、n大于capacity:插入数据+扩容
(这里扩容也有可能比要求的空间大)

在这里插入图片描述

2、n大于size小于capacity:插入数据

在这里插入图片描述

3、n小于size: 删除数据
(删除多余字符,只保留前n个字符,不会缩容)

在这里插入图片描述

当我们不指定字符插入时,就会默认插入 ‘\0’,这个过程打印不好观察,我们借助监视来看:

在这里插入图片描述

element access(数据访问)

operator[]/at

在这里插入图片描述
在这里插入图片描述

  • operator[]我们前面也介绍过,小编这里想补充的是它不同于字符数组的指针+解应用访问,对于越界的检查只是抽查行为,并且只能检查越界写。operator[]因为它是函数,所以对越界检查非常严格,我们后面学习底层会发现其实就是函数一来就用了assert断言,但是assert在release下会不起作用,并且assert是直接终止程序。
  • at功能和operator[]相同,但是它越界检查的方式是抛异常,可被捕获,不会影响程序终止。
  • 一般情况下我们还是用operator[],因为程序最开始都要走debug版,一但越界就能马上检查出来。

在这里插入图片描述

back/front

back是返回尾部位置的字符,front是返回头部位置的字符,这两个我们都用的比较少。

在这里插入图片描述

Modifiers(修改相关)

append(追加)/operator+=

在这里插入图片描述
在这里插入图片描述

我们前面介绍的push_back只能插入单字符,接下来这两个接口功能相似,都可以在string后面追加单字符、常量字符串或者string对象,但是我们更喜欢用operator+=,因为理解起来更形象。

在这里插入图片描述

assign(赋值)

在这里插入图片描述

这和我们前面介绍到的operator=功能也差不多,只是多重载了几种赋值方法。

在这里插入图片描述

insert/erase

在这里插入图片描述
在这里插入图片描述

string没有提供头部的插入删除接口,所以要实现头部或者中间部分的插入删除就需要借助这两个接口:
insert:在指定位置之前插入数据。
erase:删除指定位置及指定位置之后长度为n的字符或字符串,如果不传长度就会将这个位置及之后的所有数据全部删完,因为给了个缺省值npos(整型的最大值)。
(但是这两个接口要谨慎使用,因为string底层是数组,在数组当中插入删除就势必会挪动数据,会使时间效率变低。)

在这里插入图片描述

repalce

在这里插入图片描述

这个接口可以实现将单个字符或者字符串替换成单个字符或字符串。
(该接口也要谨慎使用,因为也有可能涉及数据的挪动)

在这里插入图片描述

String operations

c_str/data

在这里插入图片描述

在实际项目中,我们可能会遇到一些接口只能用C语言调用,比如文件操作fopen只能通过const char*类型的对象来调用,但是在C++项目中只有string,该接口就是为了解决这一问题,它能返回string在堆上的动态数组的首元素的地址。
data的功能和c_str完全一致,这也是一些历史原因造成的。

copy

在这里插入图片描述

这是拷贝接口,从pos位置开始拷贝len个字符给s,返回值是拷贝过来的有效数据个数,但是这个接口我们很少用。我们拷贝子串通常是用下面介绍的substr。

substr

在这里插入图片描述

这个拷贝接口和copy的不同在于它是用子串构造一个string对象再返回,使用更方便。

在这里插入图片描述

find/rfind

在这里插入图片描述

这是查找接口,从pos位置开始向后查找指定内容,找到了就返回找到位置下标,未找到或者找完了就返回npos。
下面这个例子就是find和replace一起使用,将字符串中所有空格字符替换为%%,pos+2目的是替换后不再从头开始找,而是从%%的下一个位置开始找,提高效率。但是replace我们都不建议用,更建议用第二种方法。

在这里插入图片描述

第二种方法就是创建一个新string,先将新空间开到和原字符串一样的大小,依次遍历原字符串若遍历到空格就插入##,若不为空格就按原字符插入。
(该方法就是以空间换时间,不用像replace那样挪动数据)

在这里插入图片描述
在这里插入图片描述

rfind基本和find一样,只不过它是从后往前找。

find_first_of/find_last_of

在这里插入图片描述

这两个接口我们用的非常少,它的功能是找到并返回目标字符串中所有你提供的字符串的字符的下标,比如下面这段代码,它能找到str中所有‘a’‘e’ ‘i’ ‘o’ 'u’的字符的下标并返回。
find_last_of是从后往前找。

  std::string str ("Please, replace the vowels in this sentence by asterisks.");std::size_t found = str.find_first_of("aeiou");while (found!=std::string::npos){str[found]='*';found=str.find_first_of("aeiou",found+1);}std::cout << str << '\n';

非成员函数

关系运算符

在这里插入图片描述

关系运算符放在非成员函数里的原因是为了支持第二种字符串与string比较的情况,因为如果是成员函数那么第一个参数必定是string(this指针)。

operator+

在这里插入图片描述

把它放在非成员函数的原因和关系运算符一样。

getline

在这里插入图片描述

这个接口是为了解决我们要提取一串字符串的情况,因为如果我们用cin提取字符串它只会提取到空格或者换行符之前,如果这段字符有多个空格比如“good morning wusaqi”,cin只会提取“good”,如果用getline就可以读一行,直到遇到换行符才终止。
我们看到它还有一个重载版本,三个参数delim可以让我们自己规定读取结束的标志字符。

三、总结

string的各种接口其实不用我们刻意去记,在用的时候慢慢熟悉就行了。 其中比较重要的接口就是增删查改+遍历:
增:operator+=/insert
删:erase
查:find
改:operator[]/迭代器

以上就是小编分享的全部内容了,如果觉得不错还请留下免费的赞和收藏
如果有建议欢迎通过评论区或私信留言,感谢您的大力支持。
一键三连好运连连哦~~

在这里插入图片描述

相关文章:

  • 区块链可投会议CCF C--IPCCC 2025 截止6.7 附录用率
  • 共享内存【Linux操作系统】
  • 【爬虫】DrissionPage-6
  • JavaScript【6】事件
  • 进阶-数据结构部分:​​​​​​​2、常用排序算法
  • 动态规划(3)学习方法论:构建思维模型
  • MATLAB2025新功能
  • 2025/517学习
  • STM32 | FreeRTOS 消息队列
  • Flink 数据传输机制
  • 6.1.1图的基本概念
  • DeepSeek快速指南:提升效率,告别内耗
  • 深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
  • OpenCV级联分类器
  • webpack 学习
  • Git 项目切换到新的远程仓库地址
  • NVMe简介6之PCIe事务层
  • 框架之下再看HTTP请求对接后端method
  • PLC和变频器之间如何接线
  • Java 快速转 C# 教程
  • 澎湃与七猫联合启动百万奖金征文,赋能非虚构与现实题材创作
  • 土耳其、美国、乌克兰三边会议开始
  • 2025年“新时代网络文明公益广告”征集展示活动在沪启动
  • “大型翻车现场”科技满满,黄骅打造现代化港口和沿海新城典范
  • 上海黄浦江挡潮闸工程建设指挥部成立,组成人员名单公布
  • 泽连斯基抵达安卡拉,称乌将派出最高级别代表团参与谈判