IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> STL-String -> 正文阅读

[C++知识库]STL-String

浅谈STL

什么是STL

标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David RMusser在惠普实验室工作时所开发出来的。虽说它主要表出现到C++中,但在被引入C++之前该技术就已经存在了很长时间。STL的代码从广义上讲分为三类:算法、容器和迭代器,细分的话还应当加上仿函数、空间配置器和配接器。几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。

为什么要使用STL

上一篇博客我们讲述了模板,通过引入模板,C++ 引申出了泛型编程技术。简单的理解泛型编程,即使用该技术编写的代码,可以支持多种数据类型。也就是说,通过泛型编程,能编写出可重复利用的程序代码,并且其运行效率和针对某特定数据类型而设计的代码相同。由此可见,C++ 很需要泛型这种新的编程模式,可以减轻编程的工作量,增强代码的重用性。

在 C++ 支持模板功能,引入了泛型编程思想的基础上,C++ 程序员们想编写出很多通用的针对不同数据类型的算法,其中 STL 脱颖而出成为 C++ 标准,并被引入 C++ 标准程序库。

STL 是一个具有高度可用性、高效的模板库,该库包含了诸多在计算机科学领域中常用的基础数据结构和算法,掌握了 STL 标准,很多功能就无需自己费心费力的去实现了(不用重复的造轮子),直接拿来用即可。

总的来说,STL 模板库是 C++ 标准程序库的重要组成部分,为 C++ 程序员提供了大量的可扩展的程序框架,高度实现了代码的可重用性,并且它是内置的,不需要额外安装,使用非常方便。

后面很长的一段时间,我们将介绍STL容器,包含string、vector、list、stack、queue…

String介绍

什么是String

string是C++、java、VB等编程语言中的字符串,字符串是一个特殊的对象,属于引用类型。 在java、C#中,String类对象创建后,字符串一旦初始化就不能更改,因为string类中所有字符串都是常量,数据是无法更改,由于string对象的不可变,所以可以共享。对String类的任何改变,都是返回一个新的String类对象。 C++标准库中string类以类型的形式对字符串进行封装,且包含了字符序列的处理操作。

为什么要使用String

大部分小伙伴应该都是从C语言入门来的,应该知道C语言中有一个char的字符类型,在那个时候我们使用char[]即字符数组的形式来表达一个字符串,那这个字符串和sting有什么区别呢?C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP思想(面向对象编程),而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

string的出现让人能够以更简单、更方便、更快捷的方式来操作字符串。

string类的底层实现

在VS2019下,我们创建一个string变量然后转到string定义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nsxcMxKJ-1652348268966)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220507094428487.png)]

可以看到string是basic_string实例化出的一个对象,那这个地方的basic_string又是个什么东西呢?我们再次选中转到定义:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wX2W7o7i-1652348268968)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220507094824870.png)]

这里可以看出basic_string实际上是一个类模板,string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits
和allocator作为basic_string的默认参数 。有关basic_string的具体实现这里就不再过多介绍,有兴趣的小伙伴可以自行了解。

这只是我们在VS中看到的现象,那怎么知道具体的细节呢?这个地方我们可以去C++官网或者cplusplus网页上查看string的具体实现。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6W39PlLW-1652348268969)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220512162529094.png)]

String类常用接口

构造函数

我们一共查询到了7个String提供的默认构造函数,目前我们只需要了解其中3个常用并且掌握即可,其他几种默认构造函数可以了解。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ANhKqu6q-1652348268970)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220512163820931.png)]

上述的三种构造函数实际上就是简单的无参构造、带参构造以及拷贝构造、具体实例可查看下述代码:

#include<iostream>
#include<string>
using namespace std;


int main()
{
	//无参构造
	string s1;
	//带参构造
	string s2("hello");
	//拷贝构造
	string s3(s2);
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	return 0;
}

其中,关于带参构造的s2也可以写成:

	string s2 = "hello";

为了验证我们直接运行下述代码:

#include<iostream>
#include<string>
using namespace std;


int main()
{
	//无参构造
	string s1;
	//带参构造
	string s2("hello");
	string s4 = "hello";
	//拷贝构造
	string s3(s2);
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-grPoULNZ-1652348268970)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220512164703396.png)]

可以看到s2 s3 s4都成功输出了hello

string的三种遍历方式

1、[]+下标

int main()
{
	string s1;
	string s2("hello");

	for (size_t i = 0; i < s2.size(); i++)
	{
		cout << s2[i] << " ";
	}
	return 0;
}

这种方式是最简单也是最容易理解的了(对于有一定C语言基础或者知道数组的小伙伴),就像访问一个数组一样即可。但是这个地方需要注意的是,这里的[]实际上是一个函数,其全程为operate[],即上述代码中的s2[i]在底层实际上会转化为:

    s2.operate[](i)

即调用了operate[]这个函数,查询文档可以看到

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dXe9eIEH-1652348268971)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220512165805829.png)]

operate[]的返回值是一个引用,这个时候有意思的地方就来了,引用返回说明了我们不仅可以读取里面的数据,还可以修改里面的数据,具体操作如下:

int main()
{
	string s1;
	string s2("hello");

	for (size_t i = 0; i < s2.size(); i++)
	{
		s2[i] = 'x';
	}
	for (size_t i = 0; i < s2.size(); i++)
	{
		cout << s2[i] << " ";
	}
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vxld81Ba-1652348268972)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220512170142448.png)]

可以看到s2里面的数据已经被修改了。

当然,当string定义为const对象时,operate[]也会重载为const,即无法修改值了。

2、迭代器

同样先给出代码:

int main()
{
	string s1;
	string s2("hello");

	//迭代器
	string::iterator it = s2.begin();
	while (it != s2.end())
	{
		cout << *it << " ";
		it++;
	}
	return 0;
}

这里需要注意的是迭代器的区间实际上是左闭右开的,其原因是因为begin是返回的第一个元素位置,但是end返回的是最后一个数据的下一个位置,所以迭代器遍历的区间实际上是在[begin(),end()),实际上C++中凡是给迭代器的区间实际上都是左闭右开的的区间,后续的容器都是这样。其次迭代器是类似指针的一个东西,具体的话等下一篇模拟实现string的时候再谈吧,迭代器可能是指针也可能不是,但它的用法就是模拟的指针。

迭代器的意义:像string,vector支持[]遍历,但是list、map等容器不支持[],我们就要使用迭代器遍历,可以理解为迭代器才是统一使用的方式,[]的遍历方式只是极个别容器的特殊遍历。

3、C++11提供的范围for

int main()
{
	string s1;
	string s2("hello");

	for (auto e : s2)
	{
		cout << e << " ";
	}
	return 0;
}

语法意义在于依次取容器中的数据赋值给e自动判断结束。后续模拟实现的时候可以知道实际上就是迭代器。需要注意的是如果需要修改的话e就需要定义为引用类型。(范围for的方式实际上可以应用到所有可以用迭代器的容器)

建议三种方式都要掌握!!!

push_back

这个接口其实看名字就应该知道实际上就是尾插,在末尾添加一个字符。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aCtSlvcK-1652348268973)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220512172421332.png)]

我就不另写代码了,直接用上述的代码添加push_back看结果:

int main()
{
	string s1;
	string s2("hello");
	s2.push_back('x');
	s2.push_back('x');
	s2.push_back('x');
	for (auto e : s2)
	{
		cout << e << " ";
	}
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mC1TMruV-1652348268973)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220512172640671.png)]

这个说实话适用性不是很高,一个字符一个字符插入未免有些呆,所以有了下面一个函数:

append

int main()
{
	string s1;
	string s2("hello");
	s2.push_back('x');
	s2.push_back('x');
	s2.push_back('x');
	s2.append("aaa");
	for (auto e : s2)
	{
		cout << e << " ";
	}
	return 0;
}

跟上一个代码区别只添加了append语句:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nHFA7MHm-1652348268974)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220512172911174.png)]

这样相比上一个push_back一个一个插入方便了许多,但是吧,C++是支持函数重载以及运算符重载的,实际上string已经重载了+=运算符,所以s2.append(“aaa”)等价于s2+="aaa"并且+=当空间不足时自动扩容,正确与否小伙伴自行测试一下吧(懒得测试了)

insert

上述的两个接口都只支持在尾部添加,那如果我想在最前面插入或者中间插入呢?这里就需要使用insert了:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GqffXUmI-1652348268974)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220512173323489.png)]

但是insert提供了7个重载版本,但是原理都是差不多的,基本上都是在指定位置或者区间插入一个字符串。需要注意的是,尽量少用insert,应该有些小伙伴接触过数据结构并且手动实现过顺序表的插入方式,其原因就在于在执行insert时底层实现的数组需要挪动数据。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-15 11:29:21  更:2022-05-15 11:30:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 18:45:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码