STL---string类

目录

一、为什么要学习string类

(1)c语言中的字符串

二、标准库中的string类

(1)string类的了解

(2)string类的常用接口说明

1.string类对象的常见构造

2.string类对象的容量操作

(1)size

(2)lengh

(3)capacity

(4)empty

(5)clear

(6)reserve

(7)resize

总结:

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

(1)重载的[ ]下标运算符

(2)at函数

(3)迭代器

1. begin和end

2.rbegin和rend

3.cbegin和cend等函数

(4)范围for

​编辑

4.string类对象的修改操作

(1)push_back

(2)append

(3)operator +=

(4)c_str

(5)find+npos和rfind

(6)substr

5.string类的非成员函数(全局函数)

(1)operator +

(2)流插入和留提取函数的重载

三、vs和g++下string结构的说明

(1)vs下的string结构

(2)g++下的string结构

四、关于string类的一道oj题

(1)反转字母

​编辑


一、为什么要学习string类

(1)c语言中的字符串

        在c语言中,字符串是以'\0'结尾的一些字符合集,为了操作方便,c标准库中提供了一些str系列的库函数,但是这些库函数是和字符串分离开来的,不太符合面相对象编程的思想,而且底层空间还需要用户自己管理,稍不注意还可能越界访问

二、标准库中的string类

(1)string类的了解

(1)字符串是表示字符序列的类

(2)标准的字符串类提供了对此类对象的支持,其接口和普通的stl类似,但添加了专门用于操作单字节字符字符串的设计特性

(3)string类是使用char作为它的字符类型,使用它的默认char_traits和分配器类型(

(4)string类是basic_string模版类的一个实例化,ta使用char来实例化basic_string模版类

(5)注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或边长字节(UTF-8)的序列,这个类的所有成员(长度和大小)以及他的迭代器,将仍然按照字节来操作,(而不是实际编码的字符)来操作

总结:

        (1)string是表示字符串的字符串类

        (2)该类的接口和常规的容器接口基本一致,但是专门添加了一些用来处理string的常规操作

        (3)string在底层的实现是:basic_string模版类的别名,

                typedef  basic_string <char, char_traits, allocator>  string

        (4)不能操作多字节或边长字节的序列

        (5)在使用stirng类的时候,必须要包含头文件#include <string>并且展开命名空间using namespace std;

(2)string类的常用接口说明

1.string类对象的常见构造

这三种写法都是符合其构造的

2.string类对象的容量操作

(1)size

这是返回字符串有效字符的长度的成员函数,当然他的长度可能与容量不同

这里我们的size就是12,因为"hello world!"刚好是12个字节,但是它的容量是多少呢?

那么有人就会问了,即使加上后面的'\0'也只是13啊,为什么会是15呢?其实这和vs中实现的string类有关,vs中底层代码中string的初始容量就是16,减去'\0'就是15了

(2)lengh

        我们还在文档中注意到了关于大小的函数还有一个lengh,但是为什么有了size还需要lengh呢?其实是因为string的出现比STL要早,在那是我们用的是lengh,后来为了和STL的使用兼容,我们才加上了一个size,总的来说他们都是返回字符串返回字符串有效字符的长度的函数,但是我们以后尽量使用size!

(3)capacity

        返回空间的总大小,在c++中的类对象都是在堆中开辟空间的(为了方便扩容)而capacity函数就是返回对象在堆中的真正空间的大小,当新插入的内容大于当前容量时,会自动扩容

(4)empty

        检测字符串是否为空串,是返回true,不是空串返回false

我们可以看到在文档中说到:empty函数不会去清理对象的空间,仅仅是判断对象是否为空,真正的清理工作需要clear函数去完成

这里s1不是空串,所以返回的是false,也就是0

(5)clear

        清空有效字符,让size变成0,但是空间不会释放

我们可以看到在s1清理后size变成了0,但是capacity仍然是15,这说明clear函数可能仅仅是把s1对象指向字符串的指针给移动了,并不会去释放它开辟的空间

(6)reserve

reserve仅仅是一个申请空间的改变的函数。如果申请的大小大于现有的capacity,则该函数会将容量提升到指定大小n(或者由于实现机制导致大于n);如果申请的大小小于现有的capacity,则不会缩容。这个函数不会改变他的长度或者改变他的内容。

可以扩容

可能不会缩容(不绝对,取决于编译器)

缩容

(7)resize

        他会调整string类对象的长度。如果n小于当前长度,会将size减小到n(移动指针)然后去除掉多余的内容;如果n大于当前长度,这个对象的空间会扩容到n(由于对齐机制,可能也会大于n),如果有指定字符c会用c去填充,如果没有指定字符,会用'\0'去填充

其实resize这个函数,在n>当前容量的时候相当于reserve+初始化;在n<当期容量的时候会移动指针减少长度,但是不会对空间大小capacity有影响

总结:

(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不会改变容量大小。

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

        遍历string类对象有几种方法,一是使用重载的[ ]或at函数;二是使用迭代器

(1)重载的[ ]下标运算符

operator [ ]让我们可以像数组一样直接访问string对象的任意下标的元素,并且由于他重载了两种函数,一个const对象调用,一个非const对象调用,所以非const对象还可以直接通过下标来修改

(2)at函数

at函数其实和operator [ ]类似,只不过其操作较为麻烦,所以我们一般都习惯于使用operator [ ]来对string类对象进行操作

(3)迭代器

        迭代器可以当做指针来使用,但是具体到每一种容器的迭代器是否真的是指针就得看他底层的代码了。

1. begin和end

2.rbegin和rend

这两个迭代器其实就是倒着走的迭代器,与上述的没什么区别,就照常当做指针使用就行,至于迭代器的++和- -等操作迭代器内部会自己封装好

3.cbegin和cend等函数

这几个函数是常量迭代器,使得该对象的任何数据不能被修改,只能用于读

(4)范围for

4.string类对象的修改操作

(1)push_back

添加一个字符到string对象的末尾处,将size+1,如果空间不够会自动扩容

(2)append

在string类对象后面追加一个字符串,其中这个字符串可以是类对象,可以是普通的字符串常亮,也可以是一段迭代器区间

文档中的size_t n是指要尾插多少个字符,如果是对于常量字符串或者string对象,就是某一段长度,如果是尾插char类型的,就是插入多少个char

(3)operator +=

operator +=是我们平时最为常用的一个接口,因为他最为符合使用习惯,而且他也重载了几种接口,让我们可以方便的使用

(4)c_str

        这是一个返回字符串地址的接口,因为c++的封装特性,我们不能直接访问类中的私有成员变量,但是可以通过公有的函数来提供字符串的地址。

        为什么要提供这样一个地址呢?直接使用string类不是更为方便吗?其实这是因为c++为了兼容c语言而设计的接口,在c语言中,我们常常会用到文件流操作等,但是系统中的很多接口都只提供了c语言的操作,并没有stirng单独的接入方式,所以我们只需要把string的真正字符串地址传递就可以和c语言一样使用了!

(5)find+npos和rfind

find是一个用来查找字符串中某个字符的函数,可以用来查找某个字符,至于他后面的缺省值pos=0默然就是从第一个位置开始找罢了,找到后返回的是该位置的下标

rfind和find大致是一样的,唯一不同的就是rfind是从后往前去找字符

(6)substr

顾名思义,substr就是在字符串中从pos的位置开始,截取n个长度的字符串,并返回截取的部分

注意:

(1)1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
(2) 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好,可以减少因为不断扩容产生的消耗。

5.string类的非成员函数(全局函数)

(1)operator +

这个函数和普通的+没有什么用法上的区别,唯一的不同就是他是用来string类对象相加的,但是我们建议少用这个运算符重载函数,因为需要传值返回,而传值返回又是深拷贝,导致效率很低

(2)流插入和留提取函数的重载

        这两个函数为什么必须要重载成全局函数而不是成员函数?我们在之前已经有提到过,因为类里面的成员函数的形参第一个位置默认会被this指针所抢占,导致如果重载成成员函数,使用习惯就和我们相反了,而在类外部就没有this指针的占位影响!

其余的函数我们用到的情况比较少,大家可以在要使用的时候查文档即可,只需要记忆有这么个功能的函数即可

三、vs和g++下string结构的说明

(1)vs下的string结构

        vs下的结构体一共占据28个字节,内部实现的稍微复杂一点,先是有一个联合体,联合体用来定义string类中的字符串的存储空间

union _Bxty
{ 
    // storage for small buffer or pointer to larger one
    value_type _Buf[_BUF_SIZE];
    pointer _Ptr;
    char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;

        (1)当字符串的长度小于16时,使用内部固定的字符数组来存放;

        (2)当字符串的长度大于16时,才会去堆上另外开辟空间,这时会用指针指向那块开辟的空间,而不使用内部固定的16个字节空间

        这种设计也是有一定的道理的,因为大多数情况下字符串的长度都是小于16,那么这时候会使用内部固定的字符数组来存放,就不需要另外开辟空间,效率较高

其次:还有一个size_t字段保存字符串的长度,一个size_t字段保存从堆上开辟空间的总容量

最后:还有一个指针做一些其他事情

故一共是16+4+4+4=28个字节

(2)g++下的string结构

        g++下的stirng结构实现的比较简单,和我们后续要模拟实现的基本一致,g++下的string是通过写时拷贝完成的,一共只有4ge字节(32位机器指针的大小就是4字节)该指针指向了一块堆开辟的空间,其中包含以下内容:

扩展了解写时拷贝

写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。
引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。

        写时拷贝能够极大程度上减少了深拷贝带来的消耗,只需要rangcount++就能代表一次空间的释放,唯一的问题就是只能读不能写,因为一旦写就会对其他的对象也造成修改,所以写时拷贝在修改时还是会去深拷贝一块空间,不过如果你不需要写只用读就赚大发啦

四、关于string类的一道oj题

(1)反转字母

关于这道题,我们可以利用霍尔排序的思想,先只找到字母,然后交换位置,直到两个指针相遇

  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STL是指标准模板库(Standard Template Library),它是C++语言的一部分,提供了一系列的模板和函数,用于支持通用的数据结构和算法。STL的目标是提供高效、可重用和可扩展的组件,以便开发人员能够更轻松地编写高质量的代码。STL包含了许多常见的数据结构,如vector、list、set、map等,以及各种算法,比如排序、查找、遍历等。通过使用STL开发人员可以更加高效地处理各种数据结构和算法的问题,提高代码的开发效率和质量。 在STL中,我们可以使用各种容器来存储和管理数据。例如,我们可以使用std::map来创建一个键值对的映射,其中每个键都有一个与之相关联的值。下面是一个示例代码,展示了如何创建和使用一个std::map对象: std::map<std::string, int> disMap() { std::map<std::string, int> tempMap{ {"C语言教程",10},{"STL教程",20} }; return tempMap; } std::map<std::string, int> newMap(disMap()); 在这个示例中,disMap()函数创建了一个临时的std::map对象,并初始化了其中的一些键值对。然后,使用移动构造函数将这个临时对象移动到了一个新的std::map对象newMap中。最终,我们可以通过newMap对象来访问和操作这些键值对。 综上所述,STLC++中的标准模板库,提供了一系列的模板和函数,用于支持通用的数据结构和算法。STL的使用可以提高代码的开发效率和质量,并且通过各种容器和算法,可以方便地处理各种数据结构和算法的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++ STL详解超全总结(快速入门STL)](https://blog.csdn.net/qq_50285142/article/details/114026148)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【C++实验】阅读STL源码并分析](https://blog.csdn.net/qq_35760825/article/details/125311509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值