文章目录
- 一、STL的简述
- 1.STL的框架
- 2.STL版本
- 二、string
- 1、string的介绍
- 2、为什么string类要实现为模板?
- 三、string的构造接口
- 四、string的容量相关的接口
- 五、string对象修改相关的接口
- 1、insert
- 2.earse
- 3、assign
- 4、replace
- 六、string对象字符串运算相关接口
- 1、c_str
- 2、find查找+substr返回子串
- 七、部分非成员函数接口
- 八、string对象与其他类型互相转换
- 1、stoi
- 2、to_string
- 九、元素访问
- 1、使用operator[]实现数组下标式的访问
- 2、迭代器读写
- 2.1正向迭代器
- 2.2反向迭代器
- 2.3const正向迭代器(不能改变*it)
- 2.4const反向迭代器(不能改变*it)
- 3、范围for读写
一、STL的简述
STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
1.STL的框架
2.STL版本
原始版本
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要阅读部分源代码,主要参考的就是这个版本。
二、string
1、string的介绍
string是管理字符数组的类。
typedef basic_string<char> string;
basic_string是模板。将basic_string这个实例重命名为string。
2、为什么string类要实现为模板?
string类本身就是一个模板,为什么要把string写成模板?是因为字符串的数组涉及编码问题,字符数组编码不同。所以需要模板。
类型 | 编码 | 类型 |
---|---|---|
string | UTF-8 | char |
wstring | Unicode | wchar_t |
u16string | UTF-16 | char16_t |
u32string | UTF-32 | char32_t |
对于字符串的多种类型,设计了basic_string模板。
string类模板的大概框架:
template <class T>
//动态增长字符数组
class basic_string
{
private:T* _str;size_t _size;size_t _capacity;
};
使用string类的时候,我们要包含头文件#include
下面我们开始说一说string类常用的接口,对于常用接口我们需要熟练使用,其他的即可查阅学习。
三、string的构造接口
函数名称 | 功能说明 |
---|---|
string() (重点) | 无参的构造,构造空字符串 |
string(const char* s) (重点) | 用C_string字符串构造对象 |
string(size_t n, char c) | 用n个字符创建对象 |
string(const string& s) (重点) | 拷贝构造 |
string (const string& str, size_t pos, size_t len = npos) | 用对象构造,下标为pos至len位置 |
string (const char* s, size_t n) | 用字符串的前n个构造对象 |
template string (InputIterator first, InputIterator last); | 迭代器区间构造 |
int main()
{string s1;//无参的构造 string s2("hello world");//用C_string字符串构造对象 string s3(3, 'x');//用3个字符创建对象string s4(s2);//拷贝构造string s5(s2, 2, 7);//用s2对象构造,下标为2开始,共7个字符构造s5,结果为llo worstring s6("hello world", 7);//用字符串构前7个字符构造string s7(s2.begin(),s2.begin()+3);//迭代器区间构造string s8 = "hehe";//构造+拷贝构造----直接构造return 0;
}
四、string的容量相关的接口
函数名称 | 功能说明 |
---|---|
size(重点) | 返回字符串的长度,不包含’\0’ |
length | 返回字符串的长度,不包含’\0’ |
capacity | 返回数组容量 |
empty(重点) | 字符串的判空 |
clear(重点) | 将size置为0,不改变容量 |
reserve(重点) | 用于预先开好空间 |
resize(重点) | 调整size的大小,可能会改变容量。多出来的位置用’\0’填充 |
注意:
1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接
口保持一致,一般情况下基本都是用size()。
2. clear()只是将string中有效字符清空,不改变底层空间大小。
3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, charc)用字符c来填充多出的元素空间。
注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参
数小于string的底层空间总大小时,reserver不会改变容量大小。
1.reserve(调整容量)
reserve用于预先开好空间,如果预开空间小于现有空间,将不会改变容量。
2.resize(调整size)
reserve和resize扩容时不会对已有的数据做改变,但缩容时会放弃超出空间的已有数据。
五、string对象修改相关的接口
函数名称 | 功能说明 |
---|---|
push_back | 尾插一个字符 |
append | 尾插字符串 |
operator+=(重点) | 字符、字符串尾插 |
insert | 在pos位置插入 |
earse | 在pos位置删除 |
assign | 对原有字符串清空后赋值 |
replace | 替换 |
1、insert
string& insert (size_t pos, const string& str);//pos位置插入string对象
string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);//pos位置插入字符对象的一部分
string& insert (size_t pos, const char* s);//pos位置插入字符串
string& insert (size_t pos, const char* s, size_t n);//pos位置插入字符串的前n个
string& insert (size_t pos, size_t n, char c);//在pos位置插入n个字符
void insert (iterator p, size_t n, char c);
iterator insert (iterator p, char c);template <class InputIterator>
void insert (iterator p, InputIterator first, InputIterator last);
2.earse
string& erase (size_t pos = 0, size_t len = npos); //从pos位置删除len个字符
iterator erase (iterator p);
iterator erase (iterator first, iterator last);
对于默认值npos:
这里的npos是-1,但是这里是无符号,实际并不是-1,是4294967295。
3、assign
assign可以理解成将原字符对象清空,重新进行赋值操作。
4、replace
repalce是对字符对象的部分取代。
六、string对象字符串运算相关接口
函数名称 | 功能说明 |
---|---|
c_str(重点) | 返回C格式字符串 |
find(重点) | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
substr(重点) | 在str中从pos位置开始,截取n个字符,然后将其返回 |
1、c_str
void Teststring()
{string str("hello");str.push_back('X'); // 在str后插入Xstr.append("world"); // 在str后追加一个字符"world"str += 'C'; // 在str后追加一个字符'C'str += "PP"; // 在str后追加一个字符串"PP"cout << str << endl;cout << str.c_str() << endl; // 以C语言的方式打印字符串
}int main()
{Teststring();return 0;
}
2、find查找+substr返回子串
size_t find (const string& str, size_t pos = 0) const;//从pos位置开始,在string对象中找str
size_t find (const char* s, size_t pos = 0) const;//从pos位置开始,在string对象中找s
size_t find (const char* s, size_t pos, size_t n) const;//从pos位置开始,在string对象中匹配s的前n个
size_t find (char c, size_t pos = 0) const;//从pos位置开始,在string对象中找字符
举例:查找.后边的内容:
//取文件后缀
//rfind()和substr
void test4()
{string file;cin >> file;size_t pos = file.rfind('.');if (pos != string::npos){string sub = file.substr(pos);cout << sub << endl;}
}
七、部分非成员函数接口
函数名称 | 功能说明 |
---|---|
operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
operator>> (重点) | 输入运算符重载 |
operator<< (重点) | 输出运算符重载 |
getline (重点) | 获取一行字符串 |
对于流插入和流提取都是以空格、换行作为结束标志的(scanf也是这个样子的)。
为了解决这个问题,我们可以采用getline,
istream& getline (istream& is, string& str, char delim);//从流提取中取出字符至str中,直至遇到delim或'\n'
istream& getline (istream& is, string& str);//从流提取中取出字符至str中
getline(std::cin,str);
遇到\n才会结束。
这个有什么用呢。比如计算 字符串最后一个单词的长度:
#include <iostream>
using namespace std;
#include <string>
int main() {string str;getline(cin,str);size_t pos = str.rfind(' ');cout<<str.size()-pos-1<<endl;
}
八、string对象与其他类型互相转换
1、stoi
将一个string对象转化为int类型的数字。
idx如果不传或者为nullptr,则表示不使用这个参数;反之,&idx指向string对象数字字符的后一个位置。
2、to_string
能够把内置类型转化为string对象。
九、元素访问
1、使用operator[]实现数组下标式的访问
int main()
{string s("hello world");//构造for (size_t i = 0; i < s.size(); ++i)//读{cout << s[i] << " ";//等价于cout << s.operator[](i) << " ";}cout<<endl;for (size_t i = 0; i < s.size(); ++i)//写{cout << (s[i] += 1) << " ";}return 0;
}
operator[]和at的区别在于operator[]是断言,at是抛异常。主要release版本assert失效。
2、迭代器读写
2.1正向迭代器
int main()
{string s("hello world");string::iterator it = s.begin();//遍历访问while (it != s.end()){cout << *it;++it;}cout << endl;it = s.begin();//将it重新置为s.begin位置//遍历修改while (it != s.end()){*it += 1;cout << *it;++it;}return 0;
}
2.2反向迭代器
int main()
{string s("hello world");string::reverse_iterator rit = s.rbegin();//遍历访问while (rit != s.rend()){cout << *rit;++rit;}cout << endl;//遍历修改rit = s.rbegin();//将rit重新置为s.rbegin位置while (rit != s.rend()){*rit += 1;cout << *rit;++rit;}return 0;
}
2.3const正向迭代器(不能改变*it)
void test(const string& s)
{string::const_iterator it = s.begin();while (it != s.end()){cout << *it;++it;}
}
2.4const反向迭代器(不能改变*it)
void test(const string& s)
{string::const_reverse_iterator rit = s.rbegin();while (rit != s.rend()){cout << *rit;++rit;}
}
3、范围for读写
int main()
{string s("hello world");//范围for的遍历访问for (auto e : s){cout << e;}cout << endl;//范围for的遍历修改for (auto& e : s){e += 1;cout << e;}return 0;
}