目录
什么是STL ?
- STL:standard template library,是C++中的标准模板库;
- 就是将常见的数据结构(顺序表、链表、堆、二叉树、哈希…)以模版方式进行封装,且包含了常见的通用的泛型算法;
- STL的内容具体有六大组件:
- 常见的STL版本:
string类
string类是什么?
- C++中用来管理字符串的类,底层通过动态顺序表实现;
- 使用时必须包含头文件
#include<string>
,及标准命名空间using namespace std
;
为什么C++要特别实现string类?
在C语言中,是没有字符串类型的,对于字符串的操作,一般是通过char*
或char[]
储存数据,并且C标准库也提供了str系列的库函数对字符串进行操作;
但C语言中,这些库函数操作与字符串是分离的(数据与方法分离),底层的空间是需要用户自己进行管理,使用繁琐且易造成越界访问;
在C++中,有了面向对象思想(OOP),可以通过类将数据和操作联系在一起,于是将对字符串的存储和操作封装成了string类,实现对字符串简单、方便、快捷的操作;
字符串都是以
\0
结尾,在C语言中,对于字符串的操作,需用户自己留意边界,防止越界访问;
但在C++中,定义的string类对象内部会自动实现对\0
标记(通过迭代器);
string类的常用接口
这里只讲解string类的常用接口,想要了解全部接口可以参考:std::string
(注:这里的接口是C++98标准的)
1. 构造与析构相关
构造(constructor)
序号 | 函数原型 | 接口介绍 |
---|---|---|
1 | string(); | 默认的无参构造函数,会生成一个空串对象 |
2 | string (const char* s); | 通过一个字符串构造一个string对象 |
3 | string (const char* s, size_t n); | 通过一个字符串的部分构造一个string对象 |
4 | string (const string& str); | 拷贝构造函数,通过string对象构造一个新对象 |
5 | string (const string& str, size_t pos, size_t len = npos); | 通过一个string对象的子串构造一个新对象 |
6 | string (size_t n, char c); | 构造一个由n个字符组成的字符串 |
7 | template <class InputIterator> string (InputIterator first, InputIterator last); | 范围构造的一个模版(利用迭代器) |
析构(destructor)
~string();
一般由编译器自动调用,用户无需重载和关注;
赋值重载(operator=)
2. 迭代器(Iterators)
string类的底层是通过动态顺序表来实现的,我们可以暂时将迭代器看作指向该顺序表元素的指针,用来遍历整个string;
- 正向迭代器
iterator begin(); 或 const_iterator begin() const;
iterator end(); 或 const_iterator end() const;
- 反向迭代器
reverse_iterator rbegin(); 或 const_reverse_iterator rbegin() const;;
reverse_iterator rend(); 或 const_reverse_iterator rend() const;
注意,所有的迭代器范围都是左闭右开的区间
除了上面的四种迭代器,C++11为了满足const元素的需求,又开辟了四种const修饰的迭代器,效果类似:(普通迭代器也可满足,这样更有标识度)
例:遍历string对象——利用迭代器
// 利用迭代器遍历string对象
int main()
{
string s("Hello!");
for (string::iterator it = s.begin(); it < s.end(); ++it)
{
cout << *it << ' ';
}
return 0;
}
3. 容量相关
序号 | 函数原型 | 接口介绍 |
---|---|---|
1 | size_t size() const; | 返回字符串有效长度 |
2 | size_t length() const; | 返回字符串有效长度 |
3 | size_t capacity() const; | 返回对象已开辟空间大小 |
4 | void resize (size_t n); 或 void resize (size_t n, char c); | 改变有效元素个数 |
5 | void reserve (size_t n = 0); | 可能改变对象容量大小,不会影响size |
6 | void clear(); | 清空有效元素,不会影响capacity值 |
7 | bool empty() const; | 检测对象是否为空串 |
【注】
-
size_t size() const;
等价于size_t length() const;
这两个函数作用完全相同,返回string字符串的有效元素个数,不包括最后的
'\0'
;之所以string会出现两个功能一样的接口,是因为
length
其实是沿用C语言的习惯而保留下来的,string类最初只有length
,引入STL之后,为了兼容又加入了size
,作为STL容器的属性存在的,符合STL的接口规则; -
resize
:修改对象有效元素
-
reserve
:扩容机制(一般由编译器自动执行该接口)
在VS2013下,string对象的默认容量为15字节;
若需要扩容,按照1.5倍大小关系扩容;
-
clear()
只是清空有效元素,不改变空间大小:
clear()并不是删除那篇空间,而是将空间的首字符设置为’\0’
4. 元素访问
例_1:遍历string对象——for循环+[ ]访问
// for循环+[]访问
int main()
{
string s("Hello!");
for (char i = 0; i < s.size(); ++i)
{
cout << s[i] << ' ';
}
return 0;
}
例_2:遍历string对象——auto+范围for循环
// auto+范围for循环
int main()
{
string s("Hello!");
for (auto a : s)
{
cout << a << ' ';
}
return 0;
}
【注】
- 字符串元素遍历总结
- 为什么元素访问的接口都要成对出现?就是必须要添加一个
const
类型的函数?
如果有一个const string
对象,是无法调用普通的元素访问接口,因为这属于权限放大,有出错风险;
- 元素访问两种方法的区别?体现在两者的越界访问机制:
- 断言和异常的区别?
5. 字符串修改
序号 | 函数原型 | 接口介绍 |
---|---|---|
1 | void push_back (char c); | 尾插字符 |
2 | string::operator+= | 拼接(尾插字符、字符串) |
3 | append | 拼接(功能很多) |
4 | insert | 任意位置插入 |
5 | erase | 任意位置删除 |
6 | void swap (string& str); | 交换两个对象 |
【注】
append
insert
erase
6. 其他操作
序号 | 函数原型 | 接口介绍 |
---|---|---|
1 | find | 找字符串元素(从前往后找) |
2 | rfind | 找字符串元素(从后往前找) |
3 | const char* c_str() const; | 字符串类转为C语言的字符指针类型 |
4 | string substr (size_t pos = 0, size_t len = npos) const; | 截取子串 |
【注】
find
rfind