目录
一. 什么是STL
二. string类的概述
三. string类的常用接口说明
3.1 字符串对象创建相关接口(构造函数)
3.2 字符串长度和容量相关接口
3.3 字符访问相关接口函数
3.4 字符串删改相关接口函数
3.5 字符查找和子串相关接口函数
3.6 迭代器相关接口函数
3.7 常用的关于string类对象的全局函数
一. 什么是STL
STL,即标准库模板(standard template library),是C++标准库的重要组成部位,是一个包含了很多经常使用的数据结构和算法的软件框架。
C++标准规定的STL有六大组件:容器、迭代器、算法、仿函数、空间配置器和配接器,其中容器就是我们常说的数据结构。

二. string类的概述
string类,是专为用于存储和操作字符串的类,使用STL string容器的接口,可以实现对字符串进行增删查改、计算长度、循环遍历等操作。string类是模板类basic_string以char为模板参数类型的一个实例,其定义为:typedef basic_string<char> string。
那么或许会有人问:字符串的每个字符不都是char类型吗,那么直接将basic_string的参数类型定义为char不就行了吗,为什么还要定义模板再实例化?
其实,我们通常认为的char类型仅仅可以表示英文字母或字符,每个char类型数据的值,通过编码表(通常为ASCII码表)与特定字符对应,由于英文字母仅有26个,加上各种可打印字符不过128个,char类型数据完全足够对英文进行编码。
但是,其他语言就不一样了,中文汉字有几万几十万,char类型数据是无法表示的。因此,为了对汉字进行编码,就引入wchar_t型数据,一个wchar_t型数据占2byte,可以表示60000多个汉字,基本可以涵盖所有常见汉字。
因此,basic_string之所以不直接将成员变量类型设为char而是采用模板,就是为了能够实例化出不同类型的模板参数,以对应不同的编码规则,从而使其适用于全世界的语言。
常见的编码规则
编码:通过值与符号表建立映射关系,从而使值可以转换为各种字符。
- ASCII码 -- 适用于英文。
- unicode -- 全世界文字的通用编码表,又称万国码。它为世界各国语言的每个字符设置了统一且唯一的二进制编码。unicode下面有包括utf-8、utf-16、utf-32这几种细化的编码规则,他们分别表示以无符号的8、16、32个二进制位的数据进行编码。
- gkb -- 为中文量身定制的编码表。
在Windows下,中文采用gkb编码规则,长字节w_char类型数据可用于中文编码。
三. string类的常用接口说明
3.1 字符串对象创建相关接口(构造函数)
- string() -- 创建空字符串对象(仅包含字符串结束标识\0)。
- string(const string& s) -- 拷贝构造,通过一个string类对象创建一个新的string类对象。注意string类的拷贝构造函数完成的是深拷贝,他会为新创建的对象再开辟一块内存空间,用于存储与s对象相同的字符,即:两者表示的字符串内容相同,但并不是存储在同一块空间的字符串。
- string(const char* s) -- 通过一个现有的字符串构造string类对象。
- string(const string& s, size_t pos, size_t len = npos) -- 通过一个string类对象的子字符串构建新的对象,子串的为:从下标pos开始为第一个字符,向后len个字符。缺省参数npos为string类的静态成员变量,值为size_t类型的-1(一个极大的数)。如果pos往后的字符数不足len,那么就用从pos往后的所有字符创建对象。
- string(const char* s, size_t n) -- 用字符串s的前n个字符构建字符串。
演示代码3.1:
int main()
{string s1; //空字符串构建string s2("abcdef"); //通过字符串创建对象string s3(s2); //通过拷贝构造创建新对象string s4(s2, 1, 3); //通过已有类对象的子串创建新对象 -- "bcd"string s5("abcdef", 3); //通过字符串的前n个字符创建新对象 -- "abc"cout << "s1 = " << s1 << endl;cout << "s2 = " << s2 << endl;cout << "s3 = " << s3 << endl;cout << "s4 = " << s4 << endl;cout << "s5 = " << s5 << endl;return 0;
}

3.2 字符串长度和容量相关接口
- size -- 获取字符串长度(不包括末尾\0),函数原型为:size_t size() const。
- length -- 获取字符串长度(不包括末尾\0),函数原型为:size_t length() const。
在string类中,size和length没有任何区别。但是,size可以用在树、链表等其他数据结构中计算数据量,而length不行。为了保证STL中各种数据结构的接口名称统一,一般建议使用size。
- capacity -- 获取当前string类对象能够存储的有效字符量,函数原型为:size_t capacity() const。
- reserve -- 将字符串空间扩容到至少一定的值,函数原型为:void reserve(size_t n)。用reserve进行扩容,并一定恰好扩容到n,而是扩容到不小于n。同时,reserve不影响字符串中原来的内容,且不对扩大的那部分空间进行初始化,如果n小于原来的capacity,那么reverse函数不进行任何工作。
- resize -- 使字符串的长度(size\length)变到n,函数原型为:void resize(size_t n)、void resize(size_t n, char ch),这两个函数构成重载。resize函数的工作为:将函数长度扩大到n,在将扩大的部分的内容改为ch,如果不给定ch值,则默认为'\0'。如果n小于原来的长度size,那么就截取前n个内容。
- clear -- 清空字符串的内容,使字符串的长度(size\length)变为0。
- empty -- 判断字符串是否为空。
演示代码3.2:
int main()
{string s1("abc");cout << "size = " << s1.size() << endl;cout << "length = " << s1.length() << endl; //获取s1的长度cout << "capacity = " << s1.capacity() << endl; //获取s1的容量cout << endl;s1.resize(10, 'x');cout << "s1 = " << s1 << endl; //abcxxxxxxxcout << "size = " << s1.size() << endl; //10cout << endl;s1.reserve(20); //将s1的容量扩大到至少20cout << "capacity = " << s1.capacity() << endl; // >=20cout << "size = " << s1.size() << endl; //3cout << endl;cout << s1.empty() << endl; //非0s1.clear(); //清空数据cout << s1.empty() << endl; //0cout << "size = " << s1.size() << endl; //0cout << "capacity = " << s1.capacity() << endl; //31return 0;
}

3.3 字符访问相关接口函数
- [] -- 下标引用操作符重载:char& operator[](size_t pos)、const char& operator[](size_t pos) const,两个函数构成重载,分别用于访问普通类对象和const类对象。
- at -- 访问指定下标位置处的字符:char& at(size_t pos)、const char& at(size_t pos) const。
重载[]和at都可以达到访问某个下标位置处字符的目的,但是,当出现越界访问时,[]会assert断言出错,at会抛异常,且[]更符合一般的编码习惯,这里推荐使用[]而不是ar。
演示代码3.3:
int main()
{string s1("abcdef");const string s2("abcdef");//使用[],将s1的每个值+1for (size_t i = 0; i < s1.size(); ++i){s1[i] += 1;}cout << s1 << endl; //bcdefg//[]访问const对象s2的每个字符,只能读不能写for (size_t i = 0; i < s2.size(); ++i){//s2[i] += 1; //报错cout << s2[i];}cout << endl;//通过at函数,遍历打印s2的每个字符for (size_t i = 0; i < s2.size(); ++i){cout << s2.at(i);}cout << endl;return 0;
}

3.4 字符串删改相关接口函数
- operator+= -- 尾插字符或字符串
- string& operator+=(const string& s) -- 通过类对象获取尾插字符串
- string& operator+=(const char* s) -- 直接尾插字符串s
- string& operator+=(char c) -- 尾插字符c
- push_back -- 尾插字符。函数原型为:void push_back(char c)
- append -- 尾插字符串或字符
- string& append(const string& s) -- 通过string类对象获取字符串尾插
- string& append(const char* s) -- 直接尾插字符串
- string& append(const string& s, size_t pos, size_t len = npos) -- 通过获取子字符串尾插
- string& append(const char* s, size_t n) -- 尾插字符串s的前n个字符
- insert -- 在指定位置插入字符或字符串
- string& insert(size_t pos, const string& s) -- 在pos下标处通过string类对象插入字符串
- string& insert(size_t pos, const string& s, size_t subpos, size_t len = npos) -- 在pos位置处插入string对象的一个子字符串
- string& insert(size_t pos, const char* s) -- 在pos下标处插入字符串s
- string& insert(size_t pos, const char* s, size_t n) -- 在pos下标处插入s的前n个字符
- string& insert(size_t pos, size_t n, char c) -- 在pos位置处插入n个c字符
- erase -- 从指定位置开始删除n个字符,函数原型:string& erase(size_t pos = 0, size_t len = npos)
演示代码3.4:
int main()
{string s1;s1 += "aaa"; //+=尾插字符串cout << s1 << endl;s1 += 'b'; //+=尾插单个字符cout << s1 << endl;s1.push_back('c'); //push_back尾插单个字符cout << s1 << endl;s1.append("ddd"); //append尾插字符串cout << s1 << endl;cout << endl;string s2("aaaaaaa");s2.insert(2, "bbbb"); //在下标2的位置插入字符串"bbbb"cout << s2 << endl;s2.erase(2, 4); //从下标为2的位置开始删除4个字符cout << s2 << endl;return 0;
}

3.5 字符查找和子串相关接口函数
- c_str -- 获取string类对象中的字符串成员(字符串首字符地址)。函数原型为:const char* c_str() const。
- find -- 以指定下标位置pos为起点,从前向后查找特定字符或子字符串,找到了返回字符或子串第一次出现的下标,找不到就返回npos。
- size_t find(const string& s, size_t pos = 0) const -- 查找sting对象s的字符串。
- size_t find(const char* s, size_t pos = 0) const -- 查找字符串s。
- size_t find(const char* s, size_t pos, size_t len) const -- 查找字符串s的一个子串。
- size_t find(char c, size_t pos = 0) const -- 查找字符c。
- refind -- 与find类似,从尾部开始,查找子字符串或字符第一次出现的下标位置。
- substr -- string substr(size_t pos = 0, size_t len = npos) -- 从当前string对象中获取子串,构建一个新的string对象。
演示代码3.5:
int main()
{string s1("abcdefgh");cout << s1.c_str() << endl; //获取字符串成员cout << s1.find("bcd") << endl; //查找子串"bcd" -- 输出1cout << s1.find("cdeg", 2, 3) << endl; //从下标2处开始查找"cdef"前3个字符构成的子串"cde" -- 输出2cout << s1.find('e') << endl; //查找字符e -- 输出4cout << endl;string s2("abcdefabcdef");cout << s2.rfind("abc", 9) << endl; //查找下标位置9之前pos最后一次出现的位置 -- 输出6cout << s2.rfind('e') << endl; //查找字符'e'最后一次出现的位置 -- 输出10string s3("abcdef");string s4 = s3.substr(1, 4);cout << "s4 = " << s4 << endl; //bcdereturn 0;
}

3.6 迭代器相关接口函数
迭代器的类型为iterator,是char*的类型重定义名称,其定义语句为:typedef char* iterator -- 对于普通对象的迭代器,typedef const char* const_iterator -- 对于const属性对象的迭代器。除了一般的iterator以外,还有反向迭代器reverse_iterator和const_reverse_iterator。
对iterator类型的变量执行++操作,其指向的位置后移一位、对reverse_iterator类型的成员变量执行++操作,其指向的位置前移一位。
- begin -- 获取指向字符串首元素的指针,函数原型为:iterator begin()和const_iterator begin() const,这两个函数构成重载,分别应用于普通对象和const属性对象。
- end -- 获取指向字符串最后一个元素后面那个位置('\0')的指针,函数原型为:iterator end()和const_iterator end() const。

- rbegin -- 返回指向字符串最后一个字符的指针,函数原型为:reverse_iterator rbegin() 和 const_reverse_iterator rbegin() const。
- rend -- 返回指向字符串第一个字符前一个位置的指针,函数原型为:reverse_iterator rend() 和 const_reverse_iterator rend() const。

演示代码3.6:
int main()
{string s1("abcde");//使用正向迭代器遍历s1的每个字符,+1后输出string::iterator it1 = s1.begin();while (it1 != s1.end()){++(*it1);cout << *it1; //输出bcdef++it1;}cout << endl;string s2("abcde");//使用反向迭代器,反向遍历s2的每个字符并输出string::reverse_iterator it2 = s2.rbegin();while (it2 != s2.rend()){cout << *it2; //输出edcba++it2;}cout << endl;return 0;
}

3.7 常用的关于string类对象的全局函数
在C语言阶段,学过函数atoi,功能是将字符串转化为整数。但是,C/C++标准库函数中并没有atoi函数,虽然大部分编译器都已支持atoi函数,但是,依然建议不要使用,这样会降低程序的可移植性,很多老式编译器依然不支持atoi。
- stoi -- 将string类对象转换为int型数据。
- stol -- 将string类对象转换为long int型数据。
- stoul -- 将string类对象转换为unsigned long int型数据。
- stoll -- 将string类对象转换为long ong型数据。
- stoull -- 将string类对象转换为转换为unsigned long long型数据。
- stof -- 将string类对象转换为float型数据。
- stod -- 将string类对象转换为double型数据。
上述函数,会自动排除字符串前部的空格,会通过'+'、'-'字符判断返回值的正负,当遇到非数字字符时,函数会终止执行,返回当前值。
注意:如果string无法转换为数字(首个非空字符不是'+'、'-'或数字字符),以及超出数据类型表示范围的情况下,上述函数均会抛异常,引发程序崩溃。
演示代码3.7:
int main()
{string s1(" -123ab1");string s2(" 1234");string s3("+1234abc");string s4("aa");string s5("-123.12");string s6("100.111abc");string s7("110.ab");string s8("001234.5");string s9("123456789987654321");cout << "s1 = " << stoi(s1) << endl; //-123cout << "s2 = " << stoi(s2) << endl; //1234cout << "s3 = " << stoi(s3) << endl; //1234//cout << "s4 = " << stoi(s4) << endl; //无法转换为int会抛异常cout << "s5 = " << stod(s5) << endl; //-123.12cout << "s6 = " << stod(s6) << endl; //110.111cout << "s7 = " << stod(s7) << endl; //110cout << "s8 = " << stod(s8) << endl; //1234.5//cout << "s9 = " << stoi(s9) << endl; //超出int范围会抛异常return 0;
}