STL 容器详解——string 类

目录

    • 传统艺能
    • 嘛是STL
    • 内容
    • 重要性
    • string 类
    • 对象的常见构造
    • string 的遍历
    • append
    • getline
    • string的拷贝
    • 两种 swap

传统艺能

小编是双非本科大一菜鸟不赘述,欢迎大佬指点江山(QQ:1319365055)
此前博客点我!点我!请搜索博主 【知晓天空之蓝】

非科班转码社区诚邀您入驻
小伙伴们,打码路上一路向北,背后烟火,彼岸之前皆是疾苦
一个人的单打独斗不如一群人的砥砺前行
这是我和梦想合伙人组建的社区,诚邀各位有志之士的加入!!
社区用户好文均加精(“标兵”文章字数2000+加精,“达人”文章字数1500+加精)
直达: 社区链接点我

倾力打造转码社区微信公众号
在这里插入图片描述


STL 容器详解——string 类_第1张图片

嘛是STL

STL是Standard Template Library的简称,标准模板库,它不仅是可复用的组件库,也是一个包罗数据结构与算法的软件框架。它是惠普实验室(HP)开发的一系列软件的统称,这可能是一个历史上最令人兴奋的工具的最无聊的术语。但是人家本这伟大的开源精神,声明允许任何人修改,拷贝,传播甚至商用但是唯一的条款就是使用者也需要开源。

STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件,STL现在是C++的一部分,因此不用额外安装什么。

惠普作为原始版本,后续悠悠大佬来进行把玩走出了三个版本
1. P.J 版本

P.J.Plauger 开发,继承HP版本,被 windows visual C+采用,不被公开和修改,可读性差,符号命名怪异,所以 windows 一直以来闭源这也是看的出来的。
2. RW 版本:

由同名公司开发,继承HP版本,被 C++ builder 采用,不被公开和修改,可读性稍稍好一点,但是 builder 是 20 年前的编译器,当时这还是个C++嘎嘎牛的编译器,只是后面被 vs 这名猛将扳倒了,中道崩殂也是实在可惜。
3. SGI 版本:

这是作为STL学习参考的主要版本,继承HP版本,被 g++(Linux) 采用,移植性好并且做了开源,阅读性也是非常的高。后面推荐去阅读侯捷老师的《STL源码剖析》,恕我直言不知道侯捷老师,你要说你是学习C++的,那必定是有水分的。
STL 容器详解——string 类_第2张图片
有人说:为何某些公司不允许使用 C++ STL?

现在 Powerpoint 早已解禁 STL,源码里面漫山遍野的模板,然而 Word 没有,代码仍然一股汇编味,一个函数调用 20 个参数五个 out…大家自己去细品

内容

STL包含六大组件
STL 容器详解——string 类_第3张图片

所谓的算法和容器就是对应我们常说的算法和数据结构,容器就是数据结构。

重要性

C++是一门很棒的语言,唯一的缺陷就是相关的库太少,不是因为大家不想为它写库,而是它的库很难写。而STL是C++v的标准模板库,里面封装了很多经典的算法,再加上是基于模板的,适用于多种数据类型,某种程度上说是通用算法,所以它在C++中的地位很高。就拿咱题目说,一个能用 C++ 解决的题,有些也支持C语言实现,但是一句 STL 能搞定上的在C里面可能会需要搞出二级指针这种属实恶心人的东西。

学 C++ 不学STL(现在叫标准程序库或许好点,后者对STL有所改进,应该算是STL的超集),一定是你人生一大遗憾,可惜现在很多学校教 C++ 的时候,根本没有提到过STL。

所以论STL重要性,这个问题本身就是个问题,不清楚 STL 地位的 C++ 学习者什么成分咱就不说了。
STL 容器详解——string 类_第4张图片

string 类

我为什么想第一个针对学习 string 类?原因很简单,早在C语言阶段就学习了字符串,为了操作方便,C语言标准库提供了一堆有关字符串操作的函数——str 系列函数,但这些函数是和字符串分开的,不太适合OOP的思想,而且底层空间需要用户自己管理,稍不留神就会越界访问。

STL 容器详解——string 类_第5张图片
从定义来看,string 类是一个 typedef 的模板,而其实库里面并不仅仅只有一种 string,还有下面这些个玩意儿:
在这里插入图片描述
为什么会有这么多派生?其实这就要牵扯到编码问题。我们知道从最早的 ASCII 码到后来的 unicode(统一码也叫万国码,世界语言的映射表),unicode 又包含了 utf-8,utf-16,utf-32,再到后来的 gbk(国标扩展,针对汉字的映射表),其实网络上的敏感词屏蔽机制就是利用了编码。

为什么 string 会设计成模板就是因为原本的 string 管理对象是 char 类型,能够很好的去兼容英文,但是像 gbk 编码的汉字就需要两个字符表示,这时就需要一个新的类来支持汉字,所以我们把 string 搞成模板就是为了适应不同的编码。

他虽然是模板,但是使用时不需要 .h 头文件,直接

#include

即可使用。他之所以不加 .h 就是因为C语言已经有一个 string.h 了,这里会产生冲突发生链接错误。当然直接使用 string 类型比如: string a 这种定义方式是错误的,因为C++标准库的东西都是放在 std 标准命名空间的。

对象的常见构造

string 类对象的构造方法有上百种,我们不可能全部记住,重点记住几个重要常见的就行了
STL 容器详解——string 类_第6张图片

int main()
{
    string s1;
    string s2("hello world");
    string s3(s2);
    string s4 = s2;
    string s5("hello world",5);//前5个元素得到 hello
    string s6(10,'a')//初始化为10个a
    string s7(s2,6,3)//从 s2 的"w"开始向后拷贝3个
}

注意无参构造 s1 里面并不是什么都没有,从底层来讲 s1 底限也会有一个 ‘\0’ 在里面。

在 s7 这种构造里面,构造表达式为

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

这里的这个 npos 又是个啥?他是个半缺省的声明,这个 npos 其实是一个成员变量
STL 容器详解——string 类_第7张图片
这里的 static const size_t npos = -1,-1 的补码是全1,给到无符号数身上就是最大值,npos 内涵就是无符号数的上限范围 4294967295,你有多少就能给你取多少。

但是总的来说并不是内容越多越好,string 类的 106 种成员接口很多都让他在C++中显得非常冗余,陈皓老师的《STL的 string 类怎么啦》一文中就对他提出了批评。

string 的遍历

其实上面对 string 的拷贝啥的都不是问题,真正的问题在于怎么去遍历 string 的每一个字符,比如我们需要做翻转 string 的操作。

遍历 string 有三种方式:

  1. 下标+[] 访问

和数组有异曲同工之妙,我们依然可以用循环的方式遍历他

for(size_t= 0;i<s1.size();i++)
{
     cout<<s1[i]<<" ";
}
  1. 迭代器
string::iterator it = s1.begin()
while(it!=s1.end())
{
   cout<<*it<<" ";
   ++it;
}

这里迭代器只做演示,后面我想专题讲解迭代器。现阶段可以认为它是个像指针或者就是指针的东西,s1 里面有一段空间,begin 返回里面内容的开头位置,而 end 不是最后一个数据而是最后一个数据的下一个位置,所以他是一个开区间,这里 while 为什么使用 != 而不用 < 呢, != 在这里是一种相对标准的语法,后面的链表或者 map,他们的迭代器并不是原生的而是封装的,用 < 就达不到目的了。

  1. 之前讲过的范围 for

范围 for 对于遍历确实方便,毕竟 auto 关键字可以自动识别类型,但是如果有需要进行走动(比如双指针靠拢的遍历)的场景就没什么大用了。

append

我们在 string 里面插入单个字符或者批量初始化为同一个字符是可以的,那可不可以插入字符串呢?答案一定是可以的,我们引入了 append 接口。

append 也和 string 一样接口一大堆,所以我们依然取其精华去其糟粕

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

但是我想告诉你,append 并不是最佳人选,真正的利器是 operator+= ,可以直接进行各种操作,又好读又好写何乐不为。

s += 'a';
s += 'YiGuBiGu';
s += str;

getline

虽然可以使用 cin 和 >> 运算符来输入字符串,但它可能会导致一些需要注意的问题。

当 cin 读取数据时,它会传递并忽略任何前导白色空格字符(空格、制表符或换行符)。一旦它接触到第一个非空格字符即开始阅读,当它读取到下一个空白字符时,它将停止读取。他的原型是:

istream& getline ( istream &is , string &str , char delim );

getline(cin,line)

这样就可以获得一个含有空格的字符串了,有人会误将 getline()作为while的判断语句,这样你会无法退出 while 循环!因为你的回车只会终止getline()函数的读入操作,getline()函数终止后又进行while()判断(即判断输入流是否有效,你的输入流当然有效,满足条件),所以又运行getline()函数。

string的拷贝

当我们需要将一个 string 内容进行操作时,我不想对他进行改动,那么我们一般会选择 new 一个新空间再用 strcpy 等方法进行拷贝,你可能会疑惑为什么不直接给目标赋值(如下)。
STL 容器详解——string 类_第8张图片

其实原因很简单,因为 string 是一个常量字符串,我们直接赋值过去也是一个完整的常量字符串个体,它就不支持增删查改这些基本属性了,所以如需操作还请仔细慎重的考虑是否直接赋值。

两种 swap

因为 string 里面有一个 swap 函数,所以我就单独拿出来说一下,这两个 swap 虽然功能都是交换内容但是内涵却不一样,他的的域不同。

string s1("hahaha");
string s2("xixixi");

s1.swap(s2);
swap(s1,s2);

相比之下,上面那个 swap 的效率就会更高,因为他的原理是交换指针,而下面那个 swap 是一个全局函数所以效率就比较低下,他的实现原理其实本质上是深拷贝,等价于这样:
STL 容器详解——string 类_第9张图片

今天先到这里吧,润了家人们。

你可能感兴趣的:(C++,STL,c++,STL,容器)