C++:String类的使用

     

                                           创作不易,感谢三连!! 

      在C语言中,我们想要存储字符串的话必须要用字符数组

char str[]="hello world"

       这其实是将在常量区的常量字符串拷贝到数组中,我们会在数组的结尾多开一个空间存储\0,这样我们如果想在访问的时候,比如打印,我们总是认为这个字符串是会读取到\0结束的

但是过于依赖\0也会有一系列的问题:

1、如果我是一个很长的字符串,但是中间有几个/0,那么我很难直接打印出来全部的字符串,因为访问到\0就会卡住

2、如果我们想通过键盘输入hello world,我们把它当成一个字符串,但是cin和scanf会默认访问到第一个空格或者是换行符就结束。

也就是说,我们的字符串如果有空格,那么还得分批次打印……

3、如果我想减少、增加、修改……这个字符串中的某些字符,也十分麻烦……如果是静态字符数组,会面临空间不够的问题,如果是动态字符数组,那么我们还要时刻注意空间的管理,稍不留神就会越界访问。

 4、虽然C语言中提供了一系列的str类的库函数,但是这些库函数都是以字符串分离开的,没有把该字符串作为一个整体,并且也容易受到\0的影响。这并不符合C++面向对象的思想。

      基于此,我们的祖师爷在想,能不能把string封装成一个类,把它像顺序表一样管理起来,给他增设一些常用的比如增删查改的函数接口?针对扩容进行检查?利用构造函数和析构函数帮助我们管理内存呢??因而我们的string类就诞生了!!

一、标准库中的string类

想要学习strling类,就要去通过他的文档去了解

string类的文档介绍

       诶!!我们发现string类竟然是一个叫做basic_strling的类模版生成的?难道string类还能有其他版本??没错!!string类有很多版本

 为什么string要有这么多版本呢??原因是这样的:

C语言最早都是由老美发明的,他们研究出了ascii码表

       为什么要发明这个东西呢??因为我们的语言和计算机的语言是不一样的,计算机只能看得懂二进制的语言,所以我们为了能让计算机看懂我们的语言,我们必须要给一个映射表, 比如我们想打印apple,那么计算机通过这个ASCII码表来匹配,比如a对应的是97 p对应的是112 l对应的是108 e对应的是101.我们通过调试转出10进制是可以验证这个结果的。

      一个字节是8个比特位,所以最多其实可以有256个表示的方法。而美国的英文字母才26个,哪怕算上大写,算上数字,算上一些符号,128个,也就是7bit就足够了!!所以ASCII码在使用英文的国家是非常友好的,每个字节都可以存储一个字符,这样就都可以表示出来。

      但是老美也想把技术推广到其他国家啊!!比如中国汉字特别多,如果全部像ASCII码表一样都按照一个字节的方式,那汉字远远不止256个啊!

      随着计算机的发展,不同国家也出现了很多字符编码,但是由于字符编码不同,计算机在不同国家之间的交流变得很困难,经常会出现乱码的问题,比如:对于同一个二进制数据,不同的编码会解析出不同的字符

     当互联网迅猛发展,地域限制打破之后,人们迫切的希望有一种统一的规则, 对所有国家和地区的字符进行编码,于是 Unicode 就出现了 

 unicode又有三个版本:

1、UTF-8

 UTF-8: 是一种变长字符编码,被定义为将码点编码为 1 至 4 个字节,具体取决于码点数值中有效二进制位的数量

UTF-8 的编码规则:

  1. 对于单字节的符号,字节的第一位设为 0,后面 7 位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的, 所以 UTF-8 能兼容 ASCII 编码,这也是互联网普遍采用 UTF-8 的原因之一
  2. 对于 n 字节的符号( n > 1),第一个字节的前 n 位都设为 1,第 n + 1 位设为 0,后面字节的前两位一律设为 10 。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码

 2、UTF-16

UTF-16 也是一种变长字符编码, 这种编码方式比较特殊, 它将字符编码成 2 字节 或者 4 字节

具体的编码规则如下:

  1. 对于 Unicode 码小于 0x10000 的字符, 使用 2 个字节存储,并且是直接存储 Unicode 码,不用进行编码转换
  2. 对于 Unicode 码在 0x10000 和 0x10FFFF 之间的字符,使用 4 个字节存储,这 4 个字节分成前后两部分,每个部分各两个字节,其中,前面两个字节的前 6 位二进制固定为 110110,后面两个字节的前 6 位二进制固定为 110111, 前后部分各剩余 10 位二进制表示符号的 Unicode 码 减去 0x10000 的结果
  3. 大于 0x10FFFF 的 Unicode 码无法用 UTF-16 编码

 3、UTF-32

      UTF-32 是固定长度的编码,始终占用 4 个字节,足以容纳所有的 Unicode 字符,所以直接存储 Unicode 码即可,不需要任何编码转换。虽然浪费了空间,但提高了效率。

       UTF-8、UTF-16、UTF-32 是 Unicode 码表示成不同的二进制格式的编码规则,同样,通过这三种编码的二进制表示,也能获得对应的 Unicode 码,有了字符的 Unicode 码,按照上面介绍的 UTF-8、UTF-16、UTF-32 的编码方法 就能转换成任一种编码了

    总结:由于UTF-8兼容ASCII,这是他的最大优势,并且在我们日常编程中很多情况只需要一个字节就可以,虽然字节存储的时候需要用一些比特位来区分该字符是几个字节的,但是从效率上来说,他可以根据具体的情况去决定用几个字节去存储,所以互联网大多采用UTF-8,而UTF-16也是变长,他的起点就是两个字节,两个字节其实可以表示完大部分国家的字符了,只有极少数古老的文字可能会需要用到4个字节。UTF-32就很粗暴,无论什么都是用4个字节,所以足够容纳所有的Unicode字符,虽然浪费了空间,但是不需要任何的编码转换,效率会比较高。但是使用得很少,在C11的时候引入了u32string。

 简单介绍GBK:

    但是微软使用的主要还是GBK,Windows支持GBK的时候UTF-8还没有普及,而微软是一家及其看重存量客户和兼容性的公司,形成了路径依赖不能轻易改变。

     GBK是大部分用两个字节表示,一些比较生僻的用三个字节表示

并且一般都是把读音类似的编在一起

      以上只是浅浅了解为什么string有这么多个版本,下面开始研究string类!!

二、string类的接口说明

2.1 string对象常见构造(constructor)

 我们研究几个比较重要的

1、string()

构造空的string对象,即空字符串

2、string(const char* s)

用C-string来构造string类对象

 其实相当于将常量字符串拷贝到str中

3、string(const string&s) 

拷贝构造函数

 

拷贝构造其实是深拷贝,因为str1和str2指向的是不同的空间

4、string(size_t n, char c)

意思是用几个相同的字符去构造

5、string (const string& str, size_t pos, size_t len = npos);

意思是,给一个string类,读取从他的第pos个位置开始往后的len个字符。

如果len给大了,就全部打印完

 我们还注意到len如果不给,会给一个缺省值nops,nops是什么呢?

 我们可以看到npos是string类里面的一个静态成员变量,他的值是-1,但是由于是size_t类型,所以转化成无符号整型是一个特别大的数

所以如果我们不传的话,也是直接拷贝完。跟传太大是一样的

 6、string (const char* s, size_t n);

 

 给一个常量字符串,从第一个位置拷贝到第n个位置

总结: 5和6易混淆,第一个传str类,然后从第pos个位置开始拷贝len个字符,第二个是传常量字符串,从第一个位置拷贝到n位置。

 2.2 string类对象的容量操作(Capacity)

 1、size和length

size和length其实是一样的, 都代表字符串的长度,但是早期STL还没出现的时候,strling类用的是length,但是后来STL出来后,里面大部分都是用的size,所以为了保持一致性又造了一个size出来,平时用哪个都可以的。

 2、capacity

表示string当前的容量,一般来说是默认不算上/0

 这边其实是16,但是capacity不会吧/0算进去。相当于capacity是实际容量-1

那string类究竟是如何扩容的呢?我们来用一段代码观察一下:

 不同编译器存在差异,因为用的STL版本可能不一样,我们看看g++

对比后我们可以看到区别:

    vs用的是PJ版STL,字符串会先被存在_Bx数组中,超过之后才会去动态开辟空间,第一次扩容是从32开始进行1.5倍扩容。而g++是SGI版STL,直接就是从0开始,然后根据情况直接开始扩容,从0开始进行2倍扩容

3、reverse

作用是提前去增加容量,扩容的效率是很低的,所以如果我们知道这个string类最多需要空间,我们一次性开好,可以减少拷贝。如果是减少的话,不会缩容。

他根据1.5倍的扩容规则,至少会扩容到超过你的要求。如果是g++的话,就是刚好到你要求的

 4、resize

会去改变size,减少的话就是变少(不会改变容量),如果增多的话就可能会扩容顺便帮助我们初始化,第一个版本的话初始化补\0,第二个版本的话就是补自己想要初始化的内容

 5、empty

 字符串为空返回1,不为空返回0

6、clear

 清楚字符串,变成空字符串(不会缩容)

7、shrink_to_fit

 意思是缩容到刚好够容纳他的有效字符个数

如上图一开始的空间是32,然后我们将size变成5,然后进行缩容到刚好够容纳他的大小

 所以前面的resize和reverse如果减少的话,都是不会改变容量大小的!!clear也不会

7、小总结

1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一
致,一般情况下基本都是用size()。
2. clear()只是将string中有效字符清空,不改变底层空间大小。
3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用\0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于
string的底层空间总大小时,reserver不会改变容量大小。

5.缩容的shrink_to_fit尽量不要用,意义不大,而且任何一个接口都不会帮我们缩容

2.3 string类对象的访问及遍历操作(Iterators

1、operator[ ] / at
 

访问下标为pos的字符,at和他是一样的功能 

 2、begin+end

获取一个字符的迭代器+获取最后一个字符的迭代器,要用到iterator(迭代器)

可以把迭代器理解成指针,begin是开始的指针,end是指向\0的指针,注意是左闭右开!! 

如果是用const类型的迭代器,就不能修改 

至此我们知道了三种可以访问的字符串的方法: 1、下标遍历 2、迭代器遍历 3、范围for

3、rbegin+rend

跟上面差不多,只不过是从尾开始访问

有没有感觉string::reverse_iterator有点难写,那用auto是不是更香

 2.4 string类对象的修改操作(Modifiers)

1、push back

尾插一个字符

2、 string::operator+= 

 3.append

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

直接尾插一个str对象

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

从这个字符串的subpos位置往后的sublen个字符尾插

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

尾插一个字符串

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

尾插字符串中的前n个字符

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

尾插n个字符

 一般来说我们更喜欢用+=,除非是一些特殊情况才会去用append

4,insert 

(1) string& insert (size_t pos, const string& str)和string& insert (size_t pos, const char* s);

从第pos个位置开始插入字符

(2)string& insert (size_t pos, const string& str, size_t subpos, size_t sublen)

是从被插入字符串中的subpos位置往后选len个字符插入

(3) string& insert (size_t pos, const char* s, size_t n);

是从被插入字符串中选前n个字符插入

(4)string& insert (size_t pos, size_t n, char c);

从第pos个位置开始插入n个相同字符

5.erase 

 从pos位置开始往后删除len个字符,不穿nops默认就pos后面全删

一般来说insert和erase都可能设计到大量数据的移动,所以不建议使用!! 

6,pop_back

尾删一个字符

7,replace

(1)string& replace (size_t pos, size_t len, const string& str)和string& replace (size_t pos, size_t len, const char* s);

将pos位置开始后面的len个字符替换成别的字符串

 (2)string& replace (size_t pos, size_t len, const string& str, size_t subpos, size_t sublen);

是从被替换字符串中的subpos位置往后选sublen个字符插入

(3)string& replace (size_t pos, size_t len, const char* s, size_t n);

是从被替换字符串中选前n个字符插入

 (4)string& replace (size_t pos, size_t len, size_t n, char c);

替换n个相同字符

8.swap

交换两个字符串

思考:

明明全局swap也可以达到交换的效果,那string里面也实现一个swap的成员函数有必要吗?? 

 

综上,要尽量使用成员函数的swap 

2.5 string类对象的操作(operations)

1、c_str(重点)

 返回一个指向C类型的字符串指针,下面介绍他的用处:

     我们可以观察到,s1.c_str()返回的其实是一个char*指针,但是为什么打印出来的不是地址呢??因为cout可以自动识别类型,对于char*类型的指针他会把它当成是字符串去处理,只要指针不是char*类型的,都会当成打印地址。

     我们会发现,当我们尾插‘\0’后再插入一些字符,打印出来的结果就不一样了,因为对于c语言来说,字符串默认是读取到\0停止,但是对于string来说,读取多少是取决于他的成员变size!!

如果string类我们想用C语言的方法处理文件,就可以用c_str 

 2、find

 找一个字符里的子串是否存在,如果存在,返回对应的第一个字符的下标,如果不存在,就会返回string::npos。

(1)(3)(4)版本差不多,区别是一个是找string类,一个是找常量字符串,一个是找字符。pos的缺省值0,不传的话就是从头开始遍历往后找,我们也可以通过pos来缩小查找的范围。

(2)版本就是 找常量字符串从pos位置开始的n个字符

 3、refind

 和find的区别就是默认是pos开始从后往前找

 4.substr

 从pos位置开始截取len个字符返回,不传len就是默认全部返回(经常和find以及rfind配合使用)

比如我们想打印出.com,我们可以先用find去定位'.'然后再打印

 如果我们不知道几个字符,s1.size()-pos刚好是剩下所有的字符,或者就干脆不传,这时候相当于就是把后面的全部打印完

有些时候要从后往前找(rfind)

 如果我们想打印中间怎么办??比如"http://www.cplusplus.com/reference/string/string/find/"我想打印出www.cplusplus.com

5.find_first_of

 找到第一个匹配的子串中任何一个字符的下标

 练习:将Please, replace the vowels in this sentence by asterisks中的abcdef全部换成*

6,find_last_of

找到最后一个与子字符串任意一个字符匹配的下标。其实可以理解从后往前找第一个

 7,find_first_not_of   / find_last_not_of

跟前两个类似,区别就是找第一个不匹配的和找最后一个不匹配的

2.6 string类对象的非成员函数

1,operator+ (string)

尽量少用,因为传值返回导致深拷贝效率很低

2,relational operators (string)

我们可以通过这些重载的操作符来比较字符串!! 

3,operator>>(string)和operator<< (string)

       值得注意的是,从c的字符串数组到c++的string类,原先读取字符串是默认读取到\0,但是封装乘string类后他有了自己的size,所以会根据size去打印,因此是可以打印出\0的,但是>>还是跟之前的scanf一样,默认以换行或者是空格作为标识,如果我们想打印出有空格的字符串,是行不通的!!

 因此我们想要流插入有空格的字符串,就得用getline

4.getline

 注意要包含string的头文件

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Consul服务注册与发现 Consul配置步骤

Consul服务注册与发现 Consul配置步骤 consul下载地址 Install | Consul | HashiCorp Developer 启动需要在 下载好的文件夹里 用cmd 运行consul agent -dev启动consul Consul配置 配置pom <!--SpringCloud consul config--> <dependency><groupId>org…

【leetcode】回文子串 动态规划

/*** param {string} s* return {number}*/ var countSubstrings function(s) {let dpnew Array(s.length).fill().map(()>new Array(s.length).fill(false));let num0;for(let i0;i<s.length;i){for(let j0;j<i;j){//在首尾相等时&#xff0c;如果长度时1或者2&…

Pegasus智能家居套件样例开发--软定时器

样例简介 此样例将演示如何在Pegasus Wi-Fi IoT智能家居套件上使用cmsis 2.0 接口进行定时器开发。 工程版本 系统版本/API版本&#xff1a;OpenHarmony 3.0 releaseIDE版本&#xff1a;DevEco Device Tool Release 3.0.0.401 快速上手 准备硬件环境 预装windows系统的PC…

26、Qt调用.py文件中的函数

一、开发环境 Qt5.12.0 Python3.7.8 64bit 二、使用 新建一个Qt项目&#xff0c;右击项目名称&#xff0c;选择“添加库” 选择“外部库”&#xff0c;点击“下一步” 点击“浏览”&#xff0c;选择Python安装目录下的libs文件夹中的“python37.lib”文件&#xff0c;点击“下…

退休开便利店真的靠谱吗?2024比较赚钱的创业项目排行

近日多个退休后开便利店赚钱的新闻登上热搜&#xff0c;但是&#xff0c;小编对此有疑问&#xff0c;退休的老年人开便利店真的是一个好选择吗&#xff1f; 第一、便利店最基本的转让费&#xff0c;装修费&#xff0c;进货等等&#xff0c;这笔开支非常大&#xff0c;足以掏空老…

终结数据混乱!开发者必学的GraphQL秘籍,高效API只需一步

在数字世界中&#xff0c;API就如同城市中的道路&#xff0c;连接着各种服务和数据。然而&#xff0c;传统的API&#xff08;如RESTful&#xff09;虽然功不可没&#xff0c;但随着技术复杂性和需求多样性不断攀升&#xff0c;它们显露出的局限性也呼唤着新的可能出现。此时&am…

LaMa Image Inpainting 图像修复 Onnx Demo

目录 介绍 效果 模型信息 项目 代码 下载 LaMa Image Inpainting 图像修复 Onnx Demo 介绍 gihub地址&#xff1a;https://github.com/advimman/lama &#x1f999; LaMa Image Inpainting, Resolution-robust Large Mask Inpainting with Fourier Convolutions, WAC…

《PyTorch深度学习实践》第十三讲RNN进阶

一、 双向循环神经网络&#xff08;Bidirectional Recurrent Neural Network&#xff0c;BiRNN&#xff09;是一种常见的循环神经网络结构。与传统的循环神经网络只考虑历史时刻的信息不同&#xff0c;双向循环神经网络不仅考虑历史时刻的信息&#xff0c;还考虑未来时刻的信息…

软件说明书怎么写?终于有人一次性说清楚了!

每次写软件说明书&#xff0c;你是不是总是毫无头绪&#xff0c;不知道从何下手&#xff1f;到各网站找资料&#xff0c;不仅格式不规范&#xff0c;甚至可能遗漏关键内容&#xff01;挨一顿批不说&#xff0c;还浪费大把时间。别着急&#xff0c;编写软件说明书&#xff0c;关…

从理论到落地,大模型评测体系综合指南

1956年夏&#xff0c;“人工智能” 这一概念被提出。距今已有近70年的发展历史。中国科学院将其划分为六个阶段&#xff1a;起步发展期&#xff08;1956年—1960s&#xff09;&#xff0c;反思发展期&#xff08;1960s-1970s&#xff09;,应用发展期&#xff08;1970s-1980s),低…

LeetCode刷题--- 乘积为正数的最长子数组长度

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述动…

Python爬虫实战第二例【二】

零.前言&#xff1a; 本文章借鉴&#xff1a;Python爬虫实战&#xff08;五&#xff09;&#xff1a;根据关键字爬取某度图片批量下载到本地&#xff08;附上完整源码&#xff09;_python爬虫下载图片-CSDN博客 大佬的文章里面有API的获取&#xff0c;在这里我就不赘述了。 一…

kitex 入门和基于grpc的使用

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于kitex系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基础系…

【Web】青少年CTF擂台挑战赛 2024 #Round 1 wp

好家伙&#xff0c;比赛结束了还有一道0解web题是吧( 随缘写点wp(简单过头&#xff0c;看个乐就好) 目录 EasyMD5 PHP的后门 PHP的XXE Easy_SQLi 雏形系统 EasyMD5 进来是个文件上传界面 说是只能上传pdf&#xff0c;那就改Content-Type为application/pdf&#xff0c;改…

11.盛最多水的容器

题目&#xff1a;给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 解题思路&#xff1a;可以…

判断闰年(1000-2000)

判断规则&#xff1a;1.能被4整除&#xff0c;不能被100整除是闰年,2.能被400整除是闰年 #include <stdio.h>int is_leap_year(int n){if((n % 400 0)||((n % 4 0)&&(n % 100 ! 0)))return 1;elsereturn 0; } int main() {int i 0;int count 0;for(i 1000;…

基于PHP的在线英语学习平台

有需要请加文章底部Q哦 可远程调试 基于PHP的在线英语学习平台 一 介绍 此在线英语学习平台基于原生PHP开发&#xff0c;数据库mysql。系统角色分为学生&#xff0c;教师和管理员。(附带参考设计文档) 技术栈&#xff1a;phpmysqlphpstudyvscode 二 功能 学生 1 注册/登录/…

kettle开发-Day43-加密环境下运行作业

前言&#xff1a; 金三银四&#xff0c;开年第一篇我们来介绍下&#xff0c;怎么在加密情况下运行我们的kettle作业及任务。无疑现在所有企业都认识到加密的重要性&#xff0c;加密后的文件在对外传输的时候不能被访问&#xff0c;访问时出现一堆乱码&#xff0c;同时正常的应用…

1分钟学会Python字符串前后缀与编解码

1.前缀和后缀 前缀和后缀指的是&#xff1a;字符串是否以指定字符开头和结尾 2.startswith() 判断字符串是否以指定字符开头&#xff0c;若是返回True&#xff0c;若不是返回False str1 "HelloPython"print(str1.startswith("Hello")) # Trueprint…

Navicat Premium 16:打破数据库界限,实现高效管理mac/win版

Navicat Premium 16是一款功能强大的数据库管理工具&#xff0c;旨在帮助用户更轻松地连接、管理和保护各种数据库。该软件支持多种数据库系统&#xff0c;如MySQL、Oracle、SQL Server、PostgreSQL等&#xff0c;并提供了直观的图形界面&#xff0c;使用户能够轻松地完成各种数…