人生建议:请手机反省一下,为什么总拉着我熬夜。
目录
STL简介
string类·容器一
auto(自动声明类型)
简介:
特点
范围for(语法糖)
简介
特点
string
string类的常见接口
1.构造
2.容量操作
3.访问和遍历
4.修改与查找
5.string类非成员函数
6.string类的大小
VS
g++
小知识
——————————————————
STL简介
STL是主要用模版写的库,是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且也是一个包罗数据结构与算法的软件框架。
全称:standard template libaray 标准模版库。
C++标准库包含很多库,如i/o流库、异常库、智能指针库等。
发展到现在,STL经过了原始版本(HP版本)、P.J版本、RW版本、SGI版本多个版本的迭代。
STL有六大组件:
容器(就是各种数据结构):string、vector、list、deque、map、set、multimap、multiset
空间配置器(给容器用的内存池):allocator
配接器:stack、queue、priority_queue
仿函数:greater、less......
算法:find、swap、reverse。sort、merge......
迭代器:iterator、const_iterator、reverse_iterator、const_reverse_iterator
string类·容器一
string由于比STL诞生的早,所以实际上属于标准库,但功能上算是容器。
auto(自动声明类型)
简介:
在C++11之前,使用auto修饰的变量,是具有自动储存器的局部变量,后来这个不重要了,C++11中,C++标准委员会赋予了auto新的含义:auto不再是一个储存类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时推导得到。
特点
1.用auto声明指针类型时,用auto和auto*没有什么区别,但用auto声明引用类型时必须加&
2.在同一语句声明多个变量时,这些变量必须是相同的类型,否则编译器会报错,因为编译器实际上只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
3.auto不能作为函数的参数,可以做返回值,但是谨慎使用,因为在读代码时需要读的人自己去函数体中找返回值,降低了代码的可读性,尽量在做返回值时给注释。
auto不能用来直接声明数组。
范围for(语法糖)
简介
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还容易犯错误。因此C++11中引入了基于范围的for循环。
特点
1.for循环后的括号中由 :分为两部分,第一部分时范围内用于迭代的变量,第二部分则表示被迭代的范围。 自动迭代,自动取数据,自动判断循环结束。
自动取arr中的数据放到ex中,自动++,自动判断结束,这里的ex的类型int也可以用auto来写。
2.范围for可以作用到数组和容器对象上进行遍历。
3.范围for的底层实际上是迭代器。
4.范围for在引用上的使用
因为是引用,所以连着a数组的值也发生了改变。
注意对自定义类型使用范围for时,会将其替换为自定义类型的迭代器,还有推荐在自定义类型时使用引用减少拷贝。
————————————————————
string
为了识别不同元素大小的串,string使用类模版来实现。
string类的常见接口
1.构造
(1)构造空的string类对象,即只有末尾自动添加的‘\0’的空字符串。
(2)用C格式的字符串来构造string类对象。
(3)string类对象中包含n个字符c
(4)拷贝构造函数
2.容量操作
(1)size 返回字符串有效字符长度,不算‘\0’
(2)length 返回字符串有效字符长度,不算'\0
size和length底层实现原理完全相同,引入size是为了与其他容器的接口保持一致,一般情况都使用size。
(3)capacity 返回空间总大小,不计算‘\0’
(4)empty 检测字符串是否为空串,是返回true,否则返回false
(5)clear 清空有效字符,但不清理空间
插入一个知识:
VS中的扩容机制:
VS是两段存储,小于16个字符存到数组里,大于等于就不在数组中存,而是动态开辟在堆区存,然后第一次动态开辟的空间是16的二倍扩容32,之后都是1.5倍扩容
linux中的扩容机制:
linux 没有两段储存,直接动态开辟在堆区存,每次扩容为2倍扩容。
(6)reserve 为字符串预留空间 ,reserve(size_t n=0) 一般用来开空间,
规则是如果n>capacity,capacity扩容到>=n,
如果n<capacity,是否缩容看编译器,但一定不会对有效数据造成影响。
比如,VS不缩容,但在linux中是n给多少就缩小到多少(在不对有效数据造成影响的前提下)。
用reserve开空间可以减少扩容小号的时间,提高效率。
(7)resize(size_t n)或(size_t n,char c) 将有效字符的个数改成n个,多出的空间如果未给指定字符用字符0填充,给指定字符用指定字符填充。
规则:
n<有效数据个数,删除数据,让size缩为n
字符串容量>n>有效数据个数 ,插入数据。
n>字符串容量,扩容+插入数据
(8)shrink_to_fit 缩容
对空间进行缩小,会将capacity 修改为 size的大小,少用,因为是异地缩容,耗费时间较多。 不过它只是一个建议,编译器会根据实际情况来选择是否缩容。
使用:字符串名.shrink_to_fit()
3.访问和遍历
(1)operator [ ] ,[ ]是一个重载的运算符,使用和数组下标相同,字符串名[下标] 即可
这里size和length均可,不过推荐size。
上面的[ ]运算符访问只能针对数组进行访问,因为只有数组才有下标。
而下面的迭代器可以用于任何的数据结构。
(2)四种迭代器
正向迭代器
begin+end begin获取一个字符的迭代器,end获取最后一个字符下一个位置的迭代器。
auto自动识别迭代器类型 可以代替string::iterator 这个类型,方便。
while条件的比较不建议用>或<,因为迭代器如果用在数据结构时,数据结构的地址不一定连续,不能直接比较地址。
反向迭代器
rbegin+rend
const 迭代器 和 const 反向迭代器
cbegin + cend crbegin + crend
使用const就不能修改这个迭代器的内容了。
注:迭代器不是指针 。 ‘ * '不是解引用,而是运算符重载。
(3)范围for 底层就是迭代器
例子上面有,这里就不放了,节省时间(不是偷懒)。
4.修改与查找
(1)push_back 在字符串后尾插字符c
会将原来'\0'的位置覆盖,然后在末尾自动添加'\0'。
(2)append 在字符串后追加一个字符串
同样会将原来‘\0’的位置覆盖,然后再末尾自动添加‘\0’。
append的多种重载函数
string (1) string& append (const string& str);就是追加一个字符串。
substring (2) string& append (const string& str, size_t subpos, size_t sublen);subpos为从传的字符串的subpos位置开始,sublen为追加长度,如果sublen大于传的字符串长度,只会追加全部传的字符串。
c-string (3) string& append (const char* s);用来面向C语言的指针类型字符串进行追加。
buffer (4) string& append (const char* s, size_t n);n为传过去的指针指向的字符串的需追加个数
fill (5) string& append (size_t n, char c);追加n个字符c
range (6) template <class InputIterator> string& append (InputIterator first, InputIterator last);支持迭代器的追加。
initializer list(7) string& append (initializer_list<char> il);
(3)operator += 在字符串后追加字符串或字符。
同理,两个string类对象相加也可以。
(4)c_str 返回C格式的字符串,也就是返回一个const char*类型的指针
(5)find(查找)大家族
find+npos find(char c , size_t pos=0) 从pos位置开始寻找字符c,找到则返回字符c的位置,未找到就返回npos,find的重载函数也如此,也可以寻找字符串。 有缺省值默认从开始位置开始找。
npos指的是size_t类型的-1,为整形最大值。
这里用有符号整形接收,所以打印出来是-1,否则就是整形最大值。
find有多种重载函数,可实现多种功能
string (1) size_t find (const string& str, size_t pos = 0) const noexcept;从pos位置开始在字符串中寻找字符串str
c-string (2) size_t find (const char* s, size_t pos = 0) const;从pos位置开始在字符串中寻找字符串s(C语言的指针格式)
buffer (3) size_t find (const char* s, size_t pos, size_type n) const;n指的是要取s这个数组中的前n个字符去和串匹配。
character (4) size_t find (char c, size_t pos = 0) const noexcept;和上面相似,在串中寻找字符。
还有其他寻找函数:
》find_first_of 功能和find重叠,重载函数与find基本相同。
》find_last_of 就是反向查找,其中pos的缺省值换为npos这个size_t 类型的-1,重载函数其余部分和find相同。
》find_first_not_of 重载函数的形式与find相同,功能为查找串中第一个与传过去的串无相同字符的位置。
》find_last_not_of 从后往前查找串中第一个与传过去的串无相同字符的位置,依旧和find_last_of相似。
》rfind ,重载函数还是和find相似,功能为将传的串反转,在串中从后向前查找传的串,返回的是成功匹配的最后一个位置,而find_last_of 返回的是成功匹配的第一个位置(从后往前的角度看)
substr 在str中从pos位置开始,截取n个字符,返回这些字符。
注:对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
5.string类非成员函数
(1)operator+ 因为传拷贝返回,所以再深拷贝时效率很低,不推荐多用。
(2)operator << 输出运算符重载 一直在使用,就不贴演示了
(3)operator >> 输入运算符重载
注意,cin默认以空格符和换行符区分多组输入。
(4)getline 未遇到换行符前可以一直获取字符串,默认以换行符为终止,可以自定义终止符。
(1) istream& getline (istream& is, string& str, char delim);(2) istream& getline (istream& is, string& str);
(5)relational operators 字符串的比较运算符重载
有 == >= <= != > < 六种 比较规则和C语言中的strcmp相似
6.string类的大小
VS
VS编译器下string类为28字节大小
构成:先是有一个联合体用来定义string中字符串的储存空间:
—当字符串长度小于16时,使用内部固定的字符数组来存放。
—当字符串长度大于等于16时,从堆上开辟空间。
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;
这种设计的好处在:大多数情况下字符串的长度都小于16,在string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过动态开辟空间,效率高。
其次:还有着一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量。
最后:还有一个指针做其他事情。
所以总共占:16+4+4+4=28个字节。
g++
g++下string的对象总共占4个字节,因为其全部由动态开辟空间来创建对象,内部只有一个指向堆空间的指针。
内部包含字段:空间总大小、字符串有效长度、引用计数、指向堆空间的指针。
struct _Rep_base
{
size_type _M_length;
size_type _M_capacity;
_Atomic_word _M_refcount;
};
小知识
1.构造函数不支持显式调用,析构函数支持。
2.在函数调用时,会开辟一块新栈帧,这个栈帧会存放函数的局部变量、参数等。
3.左开右闭相减为个数,例:数组下标0-9,,10个数据,10-0=10, 就是m-n为之间的元素数。