概念
: STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,并且是一个包括数据结构与算法的软件框架
原始版本
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)
采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高
仿函数
:
包括:grater less…算法
:
包括:find swap reverse…迭代器
:
包括:iterator const_iterator reverse_iterator…空间配置器
:
包括:allocator容器(数据结构)
:
包括:string vector list…配接器
:
包括:stack queue priority_queue
- 字符串是表示字符序列的类
- 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性
- string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)
- string类是basic_string模板类的一个实例,
它使用char来实例化basic_string模板类
,并用char_traits和allocator作为basic_string
的默认参数(根于更多的模板信息请参考basic_string)
摘自cplusplus.com
- 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,
将仍然按照字节(而不是实际编码的字符)
来操作
1 不能操作
多字节或者变长字符
的序列
2. 在使用string类时,必须包含#include头文件以及using namespace std
默认 (1)
string()
拷贝 (2)string (const string& str)
;
字串 (3)string (const string& str, size_t pos, size_t len = npos)
;
来自const字符串 (4)string (const char* s)
;
来自序列 (5)string (const char* s, size_t n)
;
填充 (6)string (size_t n, char c)
;
范围 (7)template <class InputIterator>
string (InputIterator first, InputIterator last)
;
(1) 空字符串构造函数(默认构造函数)
: 构造一个空字符串,长度为零个字符
(2)拷贝构造
:函数构造str的副本
(3)字串
: 构造函数 复制 str 从字符位置 pos 开始并跨越 len 个字符的部分(或直到 str 的结尾,如果 str 太短或 len 是 string::npos)
(4)从const字符串
: 复制s指向的空终止字符序列(C-string)
(5) 从缓冲区
: 从s所指向的字符数组中复制前n个字符
(6) 填充构造函数
:用字符c的n个连续副本填充字符串
(7) 范围构造函数
:复制范围(first,last)中的字符序列,按相同的顺序
(8) 初始化列表
:以相同的顺序复制il中的每个字符
(9) 移动构造函数
:获取str的内容 str 处于未指定但有效的状态
上面的所有构造函数都支持成员类型 allocator_type 的对象作为末尾的附加可选参数,这对于 string 是不相关的(上面未显示,请参阅 basic_string 的构造函数以获取完整签名)
示例
:int main () { std::string s0 ("Initial string"); // constructors used in the same order as described above: std::string s1; std::string s2 (s0); std::string s3 (s0, 8, 3); std::string s4 ("A character sequence"); std::string s5 ("Another character sequence", 12); std::string s6a (10, 'x'); std::string s6b (10, 43); // 43 is the ASCII code for '+' std::string s7 (s0.begin(), s0.begin()+7); std::cout << "s1: " << s1 << "\ns2: " << s2 << "\ns3: " << s3; std::cout << "\ns4: " << s4 << "\ns5: " << s5 << "\ns6a: " << s6a; std::cout << "\ns6b: " << s6b << "\ns7: " << s7 << '\n'; return 0; }
输出
:
s1:
s2: Initial string
s3: str
s4: A character sequence
s5: Another char
s6a: xxxxxxxxxx
s6b: ++++++++++
s7: Initial
名称 | 功能 |
---|---|
size | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
capacity | 返回空间总大小 |
{ string s("string"); cout<<s.size()<<endl; cout << s.length() << endl; cout << s.capacity() << endl;
注意
:
- 有效字符串长度不包括’\0’
- length是因为C语言的习惯而保留下来的,string类最初只有length,引进STL后,为了兼容,又添加了size,便于符合STL的接口规则
在使用时,size() 一般用作返回容器大小的方法,length() 一般用作返回一个序列的长度,但两者返回的结果是一样的
名称 | 功能 |
---|---|
clear | 清空有效字符 |
string s("string"); cout<<s.size()<<endl; cout << s.capacity() << endl; s.clear(); cout << s.size() << endl; cout << s.capacity() << endl;
注意
:
- 清空时只是将size清0,不改变底层空间的大小
名称 | 功能 |
---|---|
resize | 将有效字符的个数该成n个,多出的空间用字符c填充 |
string s("string"); cout<<s.size()<<endl; cout << s.capacity() << endl; s.resize(20); cout << s.size() << endl; cout << s.capacity() << endl; s.resize(4); cout << s << endl; cout << s.size() << endl; cout << s.capacity() << endl; s.resize(20,'a');//多余的用'a'填充 cout << s << endl; cout << s.size() << endl; cout << s.capacity() << endl;
注意
:
- resize多余的空间会用’\0’填充
- 空间不够会自动扩容(
所以当我们要开辟空间同时对空间初始化,可以用resize
),且VS编译器下扩容是每次按1.5倍扩(g++是一次2倍)
,后面探讨
名称 | 功能 |
---|---|
reserve | 为字符串预留空间 |
string s; cout<<s.size()<<endl; cout << s.capacity() << endl; s.reserve(200); cout << s.size() << endl; cout << s.capacity() << endl; s.reserve(100); cout << s.size() << endl; cout << s.capacity() << endl;
string s; size_t sz = s.capacity(); for (int i = 0; i < 100; ++i) { s.push_back('c'); if (sz != s.capacity()) { sz = s.capacity(); cout << "capacity: " << sz << '\n'; } }
操作
:
如果我们知道要开辟的空间大小应该一次开好,避免增容,提高效率
注意
:
- reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小
- 不要轻易使用这个函数,string的扩容和缩容都是很占用CPU的操作,对效率有影响
- string.reserve(int nSize )中nSize需要保证要能足够容纳string中的字符,否则此方法无效(注意不会崩溃)
在VS下扩容会按1.5倍扩
且string.reserve(int nSize )设置完毕后自动将string的占用空间对齐到整数步长.
比如20会对齐到2*16-1 = 31(1????)
在g++下是2倍增容
名称 | 功能 |
---|---|
empty | 检测字符串释放为空串,是返回true,否则返回false |
max_size | 返回字符串的最大大小 |
shrink_to_fit | 缩小到适合 |
具体参考:cplusplus.com string
名称 | 功能 |
---|---|
operator[] | 返回pos位置的字符,const string类对象调用 |
begin +end | begin获取一个字符的迭代器 end获取最后一个字符下一个位置的迭代器 |
rbegin +rend | begin获取一个字符的迭代器 end获取最后一个字符下一个位置的迭代器 |
范围for | C++11支持更简洁的范围for的新遍历方式 |
以下为三种遍历方式
:(需要注意的以下三种方式除了遍历string对象,还可以遍历修改string中的字符
)
注意
: 以下三种方式对于string而言,第一种使用最多string s("hello Bit"); // 1. for+operator[] for (size_t i = 0; i < s.size(); ++i) cout << s[i] << endl; // 2.迭代器 string::iterator it = s.begin(); while (it != s.end()) { cout << *it << endl; ++it; } string::reverse_iterator rit = s.rbegin(); while (rit != s.rend()) cout << *rit << endl; // 3.范围for for (auto ch : s) cout << ch << endl;
const对象要用const迭代器,只读,不能写
string s("hello"); string::const_iterator it = s.cbegin(); while (it != s.cend()) { //*it += 1; cout << *it << " "; ++it; } cout << endl;
rbegin 和 rend
string::const_iterator it = s.begin(); while (it != s.end()) { //*it += 1; cout << *it << " "; ++it; } cout << endl; //string::const_reverse_iterator rit = s.rbegin(); auto rit = s.rbegin(); while (rit != s.rend()) { //*rit += 1; cout << *rit << " "; ++rit; } cout << endl;
注意这里cbegin和cend也可以直接用begin和end(const c可以直接省略)
(C++11里增加了以下接口来匹配
)
名称 | 功能 |
---|---|
push_back | 在字符串后尾插字符c |
append | 在字符串后追加一个字符串 |
operator+= | 在字符串后追加字符串str |
insert | 少用 |
erase | 少用 |
注意insert 和erase 少用,因为数据在头部和中间时要挪动数据,效率底下
名称 | 功能 |
---|---|
c_str | 返回C格式字符串 |
string s; /*char* c; string s1 = "1234"; c = s.c_str();*///此处错误 //c_str()返回的是一个分配给const char*的地址, //其内容已设定为不可变更,如果再把此地址赋给一个可以变更内容的char*变量,就会产生冲突 char c[20]; string s1 = "1234"; strcpy(c, s.c_str()); cout << s1.c_str() << endl;
注意
:
c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同.
名称 | 功能 |
---|---|
find 和npos | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置(查找字符串中最后一次出现的内容) |
sub_str | 在str中从pos位置开始,截取n个字符,然后将其返回 |
npos
是string里面的一个静态成员变量static const size_t npos = -1;
示例(取出url中协议、域名、uri)
:string url("https://blog.csdn.net/lplp90908/article/details/49998181/"); size_t i1 = url.find("://"); if (i1 != string::npos) { string protocol = url.substr(0, i1 - 0); cout << "protocol:" << protocol << endl; } size_t i2 = url.find('/', i1 + 3); if (i2 != string::npos) { string domain = url.substr(i1 + 3, i2 - (i1 + 3)); cout << "domain:" << domain << endl; } string uri = url.substr(i2); cout << "uri:" << uri << endl;
注意
:
- 在string尾部追加字符时,s.push_back(c)/ s.append(1, c) / s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串
名称 | 功能 |
---|---|
getline | 获取一行字符串 |
getline场景
:cin遇到空格就结束读取string line; // while(cin>>line) while(getline(cin, line)) { size_t pos = line.rfind(' '); cout<<line.size()-pos-1<<endl; }
名称 | 功能 |
---|---|
operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
operator>> +operator<< | 输入运算符重载 |
relational operators | 大小比较 |