当前位置:首页 » 《随便一记》 » 正文

C++初阶:初识STL、String类接口详细讲解(万字解析)

25 人参与  2024年02月08日 08:01  分类 : 《随便一记》  评论

点击全文阅读


上次介绍完了模版和泛型编程:C++初阶:入门泛型编程(函数模板和类模板)
今天开始stl的内容了


文章目录

1.STL介绍1.1概念(标准模板库)1.2版本问题(主流有4个)1.3 STL六大组件 2.string类的基本介绍3. string类对象的构造(构造函数)4.访问及遍历操作4.1operator[ ] ([ ]加下标)4.2基于范围for4.3使用迭代器(最推荐使用) 5.string的迭代器(Iterator)5.1介绍5.2 begin()和end()(正向和常正向)5.3rbegin()和rend()(反向和常反向) 6.string类对象的容量操作6.1size和length6.2capacity6.3 reserve和rsize 7.string类对象的修改操作(+=,insert,erase)7.1重载的+=(最常用的尾插)7.2insert(效率不是很好)7.3 erase(任意位置删除) 补充:npos8.String operations函数(find,rfind,substr)8.1find8.2rfind8.3substr(截取字符串)


1.STL介绍

1.1概念(标准模板库)

STL (standard template libaray - 标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架

1.2版本问题(主流有4个)

原始版本

Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。 HP 版本–所有STL实现版本的始祖。

P. J. 版本

由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改

RW版本

由Rouge Wage公司开发,继承自HP版本,被C+ + Builder 采用,不能公开或修改,可读性一般。

SGI版本

由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版 本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。后面学习STL要阅读部分源代码,主要参考的就是这个版本

1.3 STL六大组件

容器(Containers):STL提供了多种容器,包括数组(vector)、链表(list)、双端队列(deque)、集合(set)、映射(map)等。这些容器提供了不同的数据结构,以满足各种不同的需求。算法(Algorithms):STL包含了大量的常用算法,如排序、查找、遍历等,这些算法可以用于各种容器,使得对数据的处理变得非常方便。迭代器(Iterators):迭代器是STL中用于遍历容器中元素的工具,它提供了一种统一的访问容器元素的方式,使得算法能够适用于不同类型的容器。仿函数(Functors):仿函数是一种类对象,它重载了函数调用操作符(),使得可以像函数一样调用这个类对象。STL中的很多算法都可以接受仿函数作为参数,以实现更加灵活的功能。适配器(Adapters):STL提供了一些适配器,如栈(stack)、队列(queue)、优先队列(priority_queue),它们是基于其他容器实现的高层次数据结构,提供了特定的操作接口。分配器(Allocators):分配器用于管理内存分配和释放,STL提供了一些标准的分配器,同时也允许用户定义自己的分配器,以满足特定的内存管理需求。

请添加图片描述


2.string类的基本介绍

在 C 语言中,字符串是以 null 结尾的字符数组,需要手动管理内存和处理字符串操作。string.h 头文件提供了一系列库函数,如 strlenstrcpystrcat 等,用于对字符串进行操作。但是这些函数的确与字符串是分离的,需要手动管理内存,容易出现越界访问等问题。

而在 C++ 标准库中,提供了 std::string 类,它封装了字符串的操作,提供了丰富的成员函数和运算符重载,使得字符串的操作更加方便和安全。std::string 类封装了字符串数据和长度,隐藏了内存管理的细节,提供了自动扩容、内存管理、异常安全性等功能,大大简化了字符串的操作

总结:

string是表示字符串的字符串类

该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作

实际上,std::string 是 C++ 标准库中的一部分,而 STL(标准模板库)是 C++ 标准库的子集,但是由于它和其他 STL 容器(如 std::vectorstd::list)有着相似的使用方式,因此可以将其放在一起学习和使用(出现了.length().size()计算长度的原因,一个是自带的,一个是为了与其他容器相配)

string在底层实际是:basic_string模板类的别名 typedef basic_string<char, char_traits, allocator> string,是 basic_string 类模板使用字符类型 char 实例化得到的一个类

请添加图片描述

我们使用string进行实例化时不用显示实例化,因为本身就是basic_string<char>


3. string类对象的构造(构造函数)

请添加图片描述

构造函数名称功能说明
string()构造空的string类对象,即空字符串
string(const char* s)用 C 风格的字符串(以 null 结尾的字符数组)来构造string类对象
string(size_t n, char c)string类对象中包含n个字符c
string(const string& s)拷贝构造函数
#include<iostream>using namespace std;int main(){string s1;string s2("abcd");string s3(5, 'c');string s4(s2);cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cout << s4 << endl;return 0;}

请添加图片描述


4.访问及遍历操作

4.1operator[ ] ([ ]加下标)

请添加图片描述

重载了下标操作符 [],使得可以像访问数组一样使用下标来访问字符串中的单个字符同时我们要注意返回值是char&,我们也可以进行更改等其他操作。

int main(){string s1 = "abcde";//拷贝构造for (int i = 0; i < s1.size(); ++i)//进行遍历{cout << s1[i] << " ";}cout << endl;//进行更改s1[0] = '1';cout << s1;return 0;}

请添加图片描述

4.2基于范围for

int main(){string s1 = "abcde";//拷贝构造for (auto e: s1)//只能遍历{cout << e << " ";}cout << endl;for (auto& e : s1)//想要改变,加&{e = 'a';cout << e << " ";}cout << endl;return 0;}

请添加图片描述

4.3使用迭代器(最推荐使用)

在 C++ 标准库中,std::string 类提供了迭代器,用于遍历字符串中的字符。std::string 类的迭代器类型为 std::string::iterator,它是随机访问迭代器,支持随机访问操作(还没有正式讲到它,大家现在就把他当指针)

int main(){string s1 = "abcde";//拷贝构造string::iterator it = s1.begin();//迭代器1.大多数的数据结构都有,但是[]不是都有的//2. 迭代器能跟算法一起用,下面就是结合了reverse的使用while (it != s1.end()){cout << *it << " ";it++;}return 0;}

我们还是更倾向于使用迭代器:

大多数的数据结构都有,但是[]不是都有的 而且使用[]要求物理底层是连续的 迭代器能跟算法一起用,下面给大家看看结合了reverse()(逆置)的使用
int main(){string s1 = "abcde";//拷贝构造string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";it++;}cout << endl;reverse(s1.begin(), s1.end());//开始翻转it = s1.begin();while (it != s1.end())//再次打印{cout << *it << " ";it++;}cout << endl;list<double> l1;//定义一个链表来说明,迭代器两个特点l1.push_back(1.1);l1.push_back(2.2);l1.push_back(3.3);list<double>::iterator lit=l1.begin();while (lit != l1.end()){cout << *lit << " ";lit++;}cout << endl;reverse(l1.begin(), l1.end());lit = l1.begin();while (lit != l1.end()){cout << *lit << " ";lit++;}cout << endl;return 0;}

请添加图片描述


5.string的迭代器(Iterator)

5.1介绍

迭代器是一种数据类型。在C++中,迭代器实际上是一种对象,它被设计用于在容器中进行元素的遍历和访问。迭代器为程序员提供了一种抽象的方式来访问容器中的元素,而不用关心容器的底层实现细节

请添加图片描述

迭代器名称功能说明
begin()返回一个指向字符串中第一个字符的迭代器
end()返回一个指向字符串最后一个字符下一个位置的迭代器
rbegin()反向开始,返回一个指向字符串最后一个字符的迭代器
rend()反向开始,返回一个指向字符串中第一个元素之前的位置的迭代器

std::string 类提供了多种类型的迭代器,包括正向迭代器(iterator)、常量正向迭代器(const_iterator)、反向迭代器(reverse_iterator)和常量反向迭代器(const_reverse_iterator)

正向迭代器(iterator):std::string::iterator 类型是用于遍历可修改字符串的迭代器,可以通过 begin()end() 方法获取范围常量正向迭代器(const_iterator):std::string::const_iterator 类型是用于遍历不可修改字符串的迭代器,可以通过 begin()end() 方法获取范围。反向迭代器(reverse_iterator):std::string::reverse_iterator 类型是用于以反向顺序遍历可修改字符串的迭代器,可以通过 rbegin()rend() 方法获取范围常量反向迭代器(const_reverse_iterator):std::string::const_reverse_iterator 类型是用于以反向顺序遍历不可修改字符串的迭代器,可以通过 crbegin()crend() 方法获取范围

反向用的少点

5.2 begin()和end()(正向和常正向)

请添加图片描述

begin()返回指向容器中第一个元素的迭代器

这是一个重载:

iterator begin(); 用于非常量对象,它返回一个迭代器,可以用于修改容器中的元素(可读可写)。const_iterator begin() const; 用于常量对象,它返回一个常量迭代器,用于指向容器中的元素,不允许修改容器中的元素(只读)
int main(){string s = "abcde";const string cs = "abc";string::iterator it = s.begin();//会去找最适合的,string::const_iterator it = s.begin();可以    //还是,权限不能放大,只能缩小string::const_iterator cit = cs.begin();//用string::iterator cit = cs.begin();会报错return 0;}

请添加图片描述

end()用于返回指向容器中最后一个元素之后位置的迭代器

也是两个重载,与begin()一样

5.3rbegin()和rend()(反向和常反向)

请添加图片描述

请添加图片描述

rbegin 函数返回一个反向迭代器,指向容器中最后一个元素。反向迭代器允许从容器的末尾向前遍历容器中的元素。

rend 函数返回一个反向迭代器,指向容器中第一个元素之前的位置。通常用于标记反向遍历的结束位置。

这两个也都有重载两个:反向和常量反向

所以也能看到:后面四个虽然是c11新加的东西,但是没人用


6.string类对象的容量操作

请添加图片描述

函数名称功能说明
size()(重点)返回字符串有效字符长度
length()返回字符串有效字符长度
capacity ()返回当前分给字符串空间总大小
empty() (重点)检测字符串释放为空串,是返回true,否则返回false
clear() (重点)清空有效字符
reserve() (重点)为字符串预留空间(不同版本具体实现不同,没有硬性规定)
resize (重点)将有效字符的个数该成n个,多出的空间用字符c填充

6.1size和length

二者作用其实完全相同: 返回字符串有效字符长度

为什么有两个也是历史原因了.这里推荐大家经常用size(),好与后面联系起来

int main(){string s1("abcde");cout << s1.size() << endl;cout << s1.length() << endl;return 0;}

请添加图片描述

6.2capacity

capacity() 是 C++ 中 std::string 类的一个成员函数,用于返回当前字符串对象分配的存储空间大小(即容量)。字符串对象的容量指的是在不重新分配内存的情况下,字符串可以存储的最大字符数

函数: size_t capacity() const noexcept;返回值: 一个无符号整数,表示当前字符串对象分配的存储空间大小。注意事项: capacity() 返回的是字符串对象分配的总空间,而不是当前字符串的实际长度。在执行字符串操作后,capacity() 返回的值可能会大于 size() 返回的值,因为 size() 表示实际存储的字符数,而 capacity() 表示分配的总空间
int main(){string s1("abcde");cout << s1.size() << endl;cout << s1.capacity() << endl;return 0;}

请添加图片描述

6.3 reserve和rsize

reserve(): 函数: void reserve(size_t n); 功能说明: 用于为字符串预留至少 n 个字符的存储空间,即提前分配足够的空间,但并不改变字符串的实际大小。如果 n 大于当前容量,reserve 可能导致内存重新分配,否则,它只是更新容量而无需重新分配内存 注意事项: reserve 不影响字符串的实际大小,即 size() 的值不会改变。如果 n 大于当前容量,reserve 可能会导致重新分配内存,但并不会初始化新分配的部分 n 大于原字符串的 capacity,此时 reserve 函数会将 capacity 扩容到 n;n 小于等于原字符串的 capacity(会不会缩容,看不同编译器的具体实现) resize: 函数签名: void resize(size_t n, char c = char());或者void resize (size_t n);功能说明: 将字符串的大小调整为 n,并根据需要插入或删除字符,使得字符串的实际大小等于 n。如果 n 小于当前大小,多余的字符将被删除;如果 n 大于当前大小,字符串将被扩展,并使用字符 c 填充新增的部分; 要是不写就是null characters(\0) 注意事项resize 会修改字符串的实际大小,即 size() 的值会变为 n。(可以缩小,同时也删除了)如果 n 大于当前大小,新增的部分将用字符 c 填充;要是不写就是null characters(\0) n 小于原字符串的 size,此时 resize 函数会将原字符串的 size 改为 n,也会改变字符串(删除),但不会改变 capacityn 大于原字符串的 size,但小于其 capacity,此时 resize 函数会将 size 后面的空间全部设置为字符 cn 大于原字符串的 capacity,此时 resize 函数会将原字符串扩容,然后将size 后面的空间全部设置为字符 c

请添加图片描述

int main(){string s1("abcde");s1.resize(10);cout << s1.capacity() << endl;cout << s1 << endl;s1.resize(3);cout << s1.capacity() << endl;cout << s1 << endl;return 0;}

请添加图片描述


7.string类对象的修改操作(+=,insert,erase)

请添加图片描述

7.1重载的+=(最常用的尾插)

函数: string& operator+=(const string& str);功能说明: 用于将当前字符串与另一字符串 str 进行连接,即将 str 的内容附加到当前字符串的末尾
int main(){string s1("abcde");s1 += "111";cout << s1 << endl;return 0;}

请添加图片描述

7.2insert(效率不是很好)

请添加图片描述

前者是,在pos这个下标前插入str字符串

后者是,在pos下标前插入nc

int main(){string s1 = "abc";cout << s1 << endl;s1.insert(0, "111");//0前面不就相当于头插嘛cout << s1 << endl;s1.insert(0, 2, 'x');cout << s1 << endl;return 0;}

请添加图片描述

7.3 erase(任意位置删除)

请添加图片描述

删除从下标pos处开始算起的len个字符

int main(){string s1 = "abc";cout << s1 << endl;s1.insert(0, "111");//0前面不就相当于头插嘛cout << s1 << endl;s1.insert(0, 2, 'x');cout << s1 << endl;s1.erase(0, 5);//从0处,删除5个cout << s1 << endl;return 0;}

请添加图片描述


补充:npos

请添加图片描述

npos 是 C++ 中 std::string 类的一个静态成员变量,表示无效或不存在的位置。通常用于标识字符串查找等操作未找到匹配项的情况。npos 的类型是 size_t,它是一个无符号整数类型


8.String operations函数(find,rfind,substr)

请添加图片描述

8.1find

请添加图片描述

find 用于返回 一个字符或一个字符数组或一个string对象 在 string 中首次出现的位置(返回下标),如果找不到就返回 npos

8.2rfind

整体跟find类似。从后往前找,找到一个字符或一个字符数组或一个string对象最后一次出现的位置,如果找不到就返回 npos

8.3substr(截取字符串)

请添加图片描述

pos处开始截取len长度(默认的话,截取到最后)

int main(){string s1("test.c");//得到文件后缀size_t pos1 = s1.find('.');if (pos1 != string::npos){string ret1 = s1.substr(pos1);cout << ret1 << endl;}//如果文件名含有  . 怎么办string s2("te.st.c");size_t pos2 = s2.rfind('.');if (pos2 != string::npos){string ret2 = s2.substr(pos2);cout << ret2 << endl;}return 0;}

请添加图片描述


好啦,这次就先到这里啦,以后再遇到其他的接口会继续给大家整理的。感谢大家支持!!!!


点击全文阅读


本文链接:http://zhangshiyu.com/post/67764.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1