C++STL---string知识汇总

前言

我们现在开始C++STL的学习,从这时开始我们就要锻炼自己查看英文文档的能力,每种数据结构都有上百个接口函数,我们把他们全部记下来是不可能的,所以我们只记最常见的20几个接口,其他的大概熟悉有什么功能,用的时候去查看文档。

对于string来说,实际上它就是一个管理字符数组的顺序表,因为字符数组使用的比较广泛,所以C++就专门写了一个string类,而string类最主要包含的有三个成员-----char* _str,size_t size,size_t capacity,具体的解释我们会在后面模拟实现的时候具体讲解。

上面就是string的文档解释,我们平时查阅文档使用的是cplusplus网站,这个网站现在有新的界面,但是我比较习惯使用老界面,所以我这里使用的老界面,两者本质上没有差别。

cplusplus官网:https://cplusplus.com/

我们为什么学习string类?

C语言的字符串:

C语言中,字符串是以‘\0’为结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数和字符串是分离开的,不符合OOP的思想,而且底层空间需要用户自己管理,稍不留神就容易出现访问越界的问题。

而且在OJ中,有关字符串的题目基本都会以string的形式出现,在平时工作中,为了简单方便,基本上也都使用string类,很少有人使用C库中的字符串操作函数。

标准库中的字符串

  1. string是表示字符串的字符串类
  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char,char_traits,allocator> string
  4. 不能操作多字节或变长字符的序列,因为string类独立于所使用的编码来处理字节,如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际的字符)来操作。
  5. 使用string类时,必须包含string头文件以及using namespace std;

我们通过文档可以看到两个类型,我们现在接触的是第一个。

如果我们用sizeof(char)和sizeof(wchar_t)来进行编译的话,会发现sizeof(char)为1,sizeof(wchar_t)为2。这种现象跟编码有关。

编码是什么?

计算机中只存储二进制0和1,那么我们如何表示文字呢?

对应的历史上出现很多编码表:

1.ASCII字符集

ASCII 码是最早出现的字符集,其全称为 American Standard Code for Information Interchange(美国标准信息交换代码)。它使用 7 位二进制数(一个字节的低 7 位)表示一个字符,最多能够表示 128 个不同的字符。它只能够表示英文。

2.GBK字符集

中国国家标准总局于 1980 年发布了 GB2312 字符集,其收录了 6763 个汉字,基本满足了汉字的计算机处理需要。GBK 字符集是在 GB2312 的基础上扩展得到的,它共收录了 21886 个汉字。在 GBK 的编码方案中,ASCII 字符使用一个字节表示,汉字使用两个字节表示。

3.Unicode字符集

这是一个足够完整的字符集,理论上能容纳100多万个字符,它致力于将全球范围内的语言和符号都收录其中,就可以解决跨语言环境和乱码问题了。在Unicode中,常用的字符占用两字节,有些生僻的字符占3字节甚至4字节。Unicode 是一种通用字符集,本质上是给每个字符分配一个编号(称为“码点”),但是Unicode并没有规定计算机怎么存储字符码点,那么多种长度的unicode码点同时出现在一个文本中时系统如何解析字符呢?一种直接的解决方案是将所有字符存储为等长的编码:例如,对于"hello世界"这个字符串来说,“hello”每个字符占用1字节,“世界”每个字符占用2字节,我们就可以将“hello”的每个字符的高位都填上0,这样每个字符的长度就都是两字节了,但是这样的话,会非常浪费内存空间。

4.UTF-8编码

他是一种可变长度的编码,使用1到4字节表示一个字符,根据字符的复杂性而变。ASCII 字符只需 1 字节,拉丁字母和希腊字母需要 2 字节,常用的中文字符需要 3 字节,其他的一些生僻字符需要 4 字节。

UTF-8 的编码规则并不复杂,分为以下两种情况:

  • 对于长度为 1 字节的字符,将最高位设置为 0 ,其余 7 位设置为 Unicode 码点。值得注意的是,ASCII 字符在 Unicode 字符集中占据了前 128 个码点。也就是说,UTF-8 编码可以向下兼容 ASCII 码。这意味着我们可以使用 UTF-8 来解析年代久远的 ASCII 码文本。
  • 对于长度为 n 字节的字符(其中 n>1),将首个字节的高 n 位都设置为 1 ,第 n+1 位设置为 0 ;从第二个字节开始,将每个字节的高 2 位都设置为 10 ;其余所有位用于填充字符的 Unicode 码点。

string常见接口说明

1.string类对象构造接口

(constructor)函数名称功能说明
string()---重要构造空的string类对象,即空字符串
string(const char* s)---重要

用C_str来构造string类对象

string(size_t n,char c)

string类对象中包含n个字符c

string(const string& s)---重要拷贝构造函数

需要说明的是:我们构造空的string类对象时,并不是什么都没有,会在第一个位置放\0:

2.string类对象的容量操作

函数名称功能说明
size

返回字符串有效长度

length返回字符串有效长度
capacity返回空间总大小
empty

检测字符串是否为空串,

若是返回true,不是返回false

clear清空有效字符
reserve为字符串预留空间
resize

将有效字符改为n个,

若有多出的空间用字符c填充

说明:

其中size和length的功能相同,我们比较常用size()。

对于string是在STL这个规范前被设计出来的,因此containers下并没有string:

早期要算字符串的长度,提供的接口为length,至于后面要加size接口的原因是后面增加了map,set这样的树,所以后面用length去表示他的数据个数就不合适了。

max_size

这个接口是早期设计的,属于一个没用的接口,从操作系统中获取最大的长度。本意是想告诉使用者这个字符串最大能定义多长,但这个接口在设计的时候其实不好实现,它没有办法标准的去定义这个接口,因为它有很多不确定的因素,所以这里结果是直接给2^32,也就是4G。没有什么实际价值。

capacity

对于string对象而言,若capacity是15,意味着它有16个字节的空间,因为最后有一个位置是\0。capacity会随着字符串的增大而增容。

resize

resize这里是有两个重载形式,若n小于当前字符串长度,它就会缩减到n个字符,从n开始以后的字符会被删掉。

若n大于当前字符串长度size,小于容量capacity的时候,他会在后面加上(n-size)个c字符,若n大于了capacity的话,字符串会扩容后在尾上加上(n-size)个c字符。

reserve

reserve的作用是开辟空间,即请求capacity。注意,他并不是你给多少capacity他就会给多少capacity,他在增容的时候会对照着不同编译器下自己的增容规则,最终容量不一定等于字符串长度,他可能是相等的,也可能是更大的。

当n大于字符串的capacity的时候,使用reserve会扩容。

当n小于或等于字符串的capacity的时候,使用reserve的话有可能它会缩容(开一块新空间,将数据拷贝,释放原有空间),也有可能不对当前的空间进行影响,只是改变capacity的值。经过证实:在VS下和Linux在不会缩容,STL的标准也是这样规定的,这时实现STL的人决定的。

对于s.reserve(10)这样的操作,s[9]是无效位置,因为对于operator[]来说,他会提前判断pos<_size。

我们如何使用resize和reserve函数呢?

对于resize来说,既要开空间,又要对这些空间进行初始化,就可以用resize;

对于reserve来说,如果我们明确知道我们需要多大空间,就可以提前把空间开好,以此减少增容所带来的代价,因为每次增容都是要付出代价的。

clear(清空字符串)&&empty(判断字符串是否为空)

不做过多解释,很简单

3.string类对象的访问和遍历操作

函数名称

功能说明

operator[]返回pos位置的字符
begin,end

begin获取第一个字符的迭代器,

end获取最后一个字符下一个位置的迭代器(即\0的迭代器)

rbegin,rend

rbegin获取最后一个字符的迭代器,

rend获取第一个字符上一个位置的迭代器

范围forC++11支持的更加便利的遍历方式

operator[]&&at

operator和at的结果是一样的,唯一不同的就是在越界的时候:operator[]本质上是用断言判断,如果越界了,会直接崩掉;而at若越界了则会抛异常。

范围for

这是C++11中的语法,只要支持迭代器的STL容器都可以使用范围for,我们后面会模拟它。

我们在使用范围for时,一般会使用auto类型自动判断元素类型,若我们对元素既想读又想写,就使用引用传参auto& e : s3,若只想读就使用传值传参auto e : s3。建议如果不是不能更改的情况,就使用引用传参。

迭代器

迭代器是STL中六大组件中的核心组件。

我们上面表格中介绍的begin()和end()函数,begin返回的是第一个字符的迭代器,end返回的是最后一个字符下一个位置的迭代器(即\0的迭代器)。

迭代器的用法类似于指针,不仅string有迭代器,其他容器也有迭代器,有的本质上是指针,有的不是指针,每种容器的迭代器的本质都不一样。

迭代器的好处就是我们可以使用类似的方式访问不同的支持迭代器的容器,也就是我们学习会了一种容器的迭代器就相当于也会使用了其他容器的迭代器。

对于string这类连续性的容器,我们有三种访问方式:

	string s1("123456");
第一种:
    string::iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		cout << *it1;
		it1++;
	}
	cout << endl;
第二种:
	int i = 0;
	while (i < s1.size())
	{
		cout << s1[i];
		i++;
	}
	cout << endl;
第三种:
	for (auto& e : s1)
	{
		cout << e;
	}
	cout << endl;

其实本质上只提供了两种,因为范围for本质也是迭代器,也就是说一个容器支持迭代器才会支持范围for。

operator[]可以像数组一样去访问,这种方式对于string,vector这样的数据结构是支持的,但是不支持list这样不连续的结构。

迭代器的分类

迭代器实际上可以看成两种大的区分方法:1.是否为const  2.是否为反向

void print(string& s)//正向打印普通对象
{
	string::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it;
		it++;
	}
	cout << endl;
}

void print_const(const string& s)正向打印const对象
{
	string::const_iterator cit = s.cbegin();
	while (cit != s.cend())
	{
		cout << *cit;
		cit++;
	}
	cout << endl;
}


void print_reverse(string& s)//逆向打印普通对象
{
	string::reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit;
		rit++;
	}
	cout << endl;
}

void print_const_reverse(const string& s)//逆向打印const对象
{
	string::const_reverse_iterator crit = s.crbegin();
	while (crit != s.crend())
	{
		cout << *crit;
		crit++;
	}
	cout << endl;
}

我们需要注意的是:无论是使用正向迭代器,还是反向迭代器,我们便利容器都是对迭代器进行++,而不是--。

4.string类对象的修改操作

push_back && append && operator+=

这三个操作符都是有关尾插的操作符,push_back是尾插一个字符,append是尾插一个字符串(但是它重载的太复杂了),前面这俩实际中都没有operator+=好用,因为operator+=可以追加一个字符,也可以追加一个字符串。

insert (插入数据)&& erase(删除数据)

对于insert,我们能不用就不用,因为string本质上是个保存字符的数组,所以中间插入删除数据就需要挪动数据,代价很大。

对于erase,我们会注意他有一个缺省参数npos,npos是string这个类里的静态成员变量,他的值是-1。但是它是size_t类型,是无符号的,所以通过补码转换,他就是long long int能表示的最大正整数2^64。

find && rfind

find和rfind都是查找函数,除了查找单个字符外还可以查找子字符串,返回值是查找的元素的下标,一般是int,若找不到则返回npos即一个极大的整数。

其中参数pos则是调用查找函数时开始查找的位置,find函数默认pos为0,rfind函数默认pos为npos。find是从前向后查找第一个字符或字符串;rfind则是从右往左查找,相当于查找最后一个字符或字符串的位置,返回值也是该字符或子字符串在字符串中的位置。

substr

生成子字符串。

c_str

返回string对象中的C数组,用于和C语言合用。

5.string类非成员函数

函数功能说明
operator+最好少用,这是传值返回,深拷贝效率低
operator>>输入运算符重载
operator<<输出运算符重载
getline获取一行字符串
relational operators比较大小

operator+ && operator+=

这两个的作用都是尾插,但是+不会改变当前字符串,而+=会改变当前字符串。

(对比一下,operator+返回的是string,operator+=返回的是string&)

relational operators

这并不是一个函数,而是一批函数。string提供的这批函数是用来比较字符串大小的,有很多的版本,例如:有string对象和string对象比的,还有C语言字符串和string对象比的等。实际上,这比较冗杂,因为C语言字符串是可以被隐式类型转换成string对象:

string s1("1111");
//正常写法,string支持单参数的构造函数

string s2 = "2222";
//隐式类型转换,早先是先将C语言字符串构造一个string,再将string拷贝构造s2。
//但现在编译器都已经优化成直接构造了

6.补充

to_string (数值转字符串)&& stoi(字符串转数值)

对于to_string,在C语言中有类似的itoa,但是它需要自己提供空间,且它并不是标准的C库,所以导致我们刷题的时候部分OJ是不支持的。

对于stoi:

不仅有stoi用来将string对象转化为int类型,还有将string对象转化为long,或long long 等对象返回的函数:

这就是本章的全部内容,下篇文章我们将介绍string的模拟实现,文章有什么不足请大家指出,谢谢大家!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/647258.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

奇舞周刊第529期:万字长文入门前端全球化

周五快乐&#xff08;图片由midjourney生成&#xff09; 奇舞推荐 ■ ■ ■ 万字长文入门前端全球化 目前国内企业正积极开拓国际市场&#xff0c;国际化已成为重要的发展方向&#xff0c;因此产品设计和开发更需考虑国际化。本文介绍了语言标识、文字阅读顺序等诸多知识。然后…

卡特兰数-

是组合数学中一种常出现于各种计数问题中的数列。 一、简单介绍 卡特兰数是一个数列&#xff0c;其前几项为&#xff08;从第零项开始&#xff09; : 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 47763…

LeetCode:279.完全平方数

class Solution:def numSquares(self, n: int) -> int:dp[i for i in range(n1)]for i in range(2,n1):for j in range(1,int(i**(0.5))1):dp[i]min(dp[i],dp[i-j*j]1)return dp[-1]代码解释 初始化 DP 数组&#xff1a; dp [i for i in range(n1)] 这里&#xff0c;dp[i]…

OpenAI策略:指令层级系统让大模型免于恶意攻击

现代的大模型&#xff08;LLMs&#xff09;不再仅仅是简单的自动完成系统&#xff0c;它们有潜力赋能各种代理应用&#xff0c;如网页代理、电子邮件秘书、虚拟助手等。然而&#xff0c;这些应用广泛部署的一个主要风险是敌手可能诱使模型执行不安全或灾难性的行动&#xff0c;…

探索集合python(Set)的神秘面纱:它与字典有何不同?

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、集合&#xff08;Set&#xff09;与字典&#xff08;Dictionary&#xff09;的初识 1. …

元组的创建和删除

目录 使用赋值运算符直接创建元组 创建空元组 创建数值元组 删除元组 自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 元组&#xff08;tuple&#xff09;是Python中另一个重要的序列结构&#…

太空几乎没有阻力,飞船理论上能一直加速,为何还说星际旅行很难

太空几乎没有阻力&#xff0c;飞船理论上能一直加速&#xff0c;为何还说星际旅行很难&#xff1f; 答案 现代科学认为&#xff0c;我们的地球诞生于46亿年前&#xff0c;也就是太阳系诞生初期&#xff0c;在太阳系中一共有八大行星&#xff0c;而地球是唯一一颗诞生了生命的…

性能测试学习之基本概念和认识(一)

一、概念 1.性能测试&#xff1a;使用自动化工具&#xff0c;模拟不同场景&#xff0c;对软件各项性能指标进行测试和评估的过程 2.包括&#xff1a;a.后台处理程序的性能&#xff1b;b.应用服务器、数据库、架构设计是否存在瓶颈&#xff1b;c.服务器资源消耗(CPU、内存、磁…

游戏行业 2024 Q1报告 | 国内同比上升7.6%,海外收入同比环比双增长,码住!

作为中国音像与数字出版协会主管的中国游戏产业研究院的战略合作伙伴&#xff0c;伽马数据发布了《2024年1—3月中国游戏产业季度报告》。 数据显示&#xff0c; 2024年1—3月&#xff0c;中国游戏市场实际销售收入726.38亿元&#xff0c;同比增长7.60%&#xff0c;主要受移动游…

Linux防火墙之iptables(二)

一.SNAT策略概述 1.SNAT 策略的典型应用环境 局域网主机共享单个公网IP地址接入Internet&#xff08;私有IP不能在Internet中正常路由&#xff09; 局域共享上网 2.SNAT 策略的原理 源地址转换&#xff0c;Source Network Address Translation 修改数据包的源地址 未作SNAT转换…

一.架构设计

架构采用 ddd 架构&#xff0c;不同于传统简单的三层的架构&#xff0c;其分层的思想对于大家日后都是很有好处的&#xff0c;会给大家的思想层级&#xff0c;提高很多。 传统的项目 现有的架构 采取ddd架构&#xff0c;给大家在复杂基础上简化保留精髓&#xff0c;一步步进行…

TOTP 算法实现:双因素认证的基石(C/C++代码实现)

双因素认证&#xff08;Two-Factor Authentication, 2FA&#xff09;扮演着至关重要的角色。它像是一道额外的防线&#xff0c;确保即便密码被窃取&#xff0c;不法分子也难以轻易突破。在众多双因素认证技术中&#xff0c;基于时间的一次性密码&#xff08;Time-Based One-Tim…

【古董技术】ms-dos应用程序的结构

序 制定一个MS-DOS应用程序计划需要认真分析程序的大小。这种分析可以帮助程序员确定MS-DOS支持的两种程序风格中哪一种最适合该应用程序。.EXE程序结构为大型程序提供了好处&#xff0c;因为所有.EXE文件之前都有额外的512字节&#xff08;或更多&#xff09;的文件头。另一方…

【MinIO学习】

OSS Docker podman MinIO服务器 MinIO客户端 Bucket Object 时间同步 The difference between the request time and the servers time is too large。 URL

AGI系列(1):掌握AI大模型提示词优化术,提问准确率飙升秘籍

当我们向AI大模型提问时&#xff0c;通常人们的做法是有什么问题&#xff0c;就直接去问&#xff0c;得到大模型的回复结果&#xff0c;时好时坏&#xff0c;完全没有可控性。 那么有没有一种方式或是一套方法&#xff0c;可以让我们向大模型提问时&#xff0c;得到的结果更准确…

二十九篇:构建未来:信息系统的核心框架与应用

构建未来&#xff1a;信息系统的核心框架与应用 1. 引言 在这个充满挑战和机遇的信息时代&#xff0c;信息系统已经成为现代组织不可或缺的神经中枢。它们不仅革新了我们处理信息的方式&#xff0c;更是极大地增强了决策制定的效率和质量。在这篇文章中&#xff0c;我将分享我…

JMeter学习笔记二

面试题&#xff1a; 1.做接口测试时&#xff0c;你是怎么做的数据校验(返回值验证)&#xff1f;一般你会验证哪些数据&#xff1f; 校验code 200&#xff08;说明后端接到了你的请求&#xff0c;并且给了应答&#xff09; 返回信息 sucess 2.有1w个用户名密码需要登录&#xff…

搭建Harbor镜像仓库

前言 1、系统版本&#xff1a;CentOS9 2、harbor版本&#xff1a;v2.9.4 3、提前安装好docker和docker-compose&#xff0c;参考地址。我这里安装的版本是docker&#xff1a;26.1.3 docker-compose&#xff1a;v2.27.1 安装步骤 下载安装包 1、下载地址&#xff1a;ha…

基于门控的循环神经网络:GRU

门控循环单元&#xff08;GatedRecurrentUnit&#xff0c;GRU&#xff09;网络&#xff0c;也是一种基于门控的循环神经网络&#xff0c;但是名气不如LSTM大&#xff0c;GRU是对LSTM的一种改版&#xff0c;可以理解为是LSTM的简化版。LSTM有三个门&#xff0c;输入门&#xff0…

代码随想录-Day20

654. 最大二叉树 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums…