顺序容器2(用法)
顺序容器类型:
vector 可变大小数组。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢
deque 双端队列。支持快速随机访问。在头尾位置插入/删除速度很快
list 双向列表。只支持双向顺序访问。在 list 中任何位置进行插入/删除操作速度都很快
forward_list 单向链表。只支持单向顺序访问。在链表任何位置进行插入/删除操作都很快
array 固定大小数组。支持快速随机访问。不能添加或删除元素
string 与 vector 相似的容器,但专门用于保存字符。随机访问快。在尾部插入/删除速度很快
容器操作(后面再提具体每个容器操作对元素的其他限制):
类型别名
iterator 此容器的迭代器类型
const_iterator 可以读取元素,但不能修改元素的迭代器类型
size_type 无符号整数类型,足够保存此种容器类型最大可能容器大小
difference_type 带符号整数类型,足够保存两个迭代器之间的距离
value_type 元素类型
reference 元素的左值类型,与 value_type& 含义相同
const_reference 元素的 const 左值类型,即 const value_type&
构造函数
C c; 默认构造函数,构造空容器
C c1(c2); 构造 c2 的拷贝 c1
C c(b, e); 构造 c,将迭代器 b 到 e 指定的范围内的元素拷贝到 c(array 不支持)
C c{a, b, c, d...} 列表初始化 c
赋值与 swap
c1 = c2; 将 c1 中的元素替换为 c2 中的元素
c1 = {a, b, c, d...} 将 c1 中的元素替换为列表中元素(不适用于 array)
a.swap(b); 交换 a 和 b 的元素
swap(a, b); 等价于 a.swap(b)
大小
c.size(); c 中元素的数目(不支持 forward_list)
c.max_size(); c 中可保存的最大数目的元素数目
c.empty(); 若 c 中存储了元素,返回 false,否则返回 true
添加/删除元素(不适用于 array)
注:在不同容器中,这些操作的接口都不同
c.insert(args); 将 args 中的元素拷贝进 c
c.emplace(inits); 使用 inits 构造 c 中的一个元素
c.erase(args); 删除 args 指定的元素
c.clear(); 删除 c 中所有元素,返回 void
关系运算符
==,!= 所有容器都支持
<,<=,>,>= 关系运算(无序关联容器不支持)
获取迭代器
c.begin(),c.end() 返回 c 的首元素和尾元素之后位置的迭代器
c.cbegin(),c.cend() 返回 const_iterator
反向容器的额外成员(不支持 forward_list)
reverse_iterator 按逆序寻址元素的迭代器
const_reverse_iterator 不能修改元素的逆序迭代器
c.rbegin(),c.rend() 返回指向 c 尾元素和首元素之前位置的迭代器
c.crbegin(),c.crend() 返回 const_reverse_iterator
虽然我们可以在容器中保存几乎任何类型,但某些容器操作对元素类型有自己的特殊要求。我们可以为不支持特定操作需求的类型定义容器,但这种情况下就只能使用那些没有特殊要求的容器操作了:
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 class no_default{//no_default 是一个没有默认构造函数的类型 6 int x; 7 public: 8 no_default(int a) : x(a){} 9 ~no_default(){} 10 }; 11 12 int main(void){ 13 int init = 1; 14 std::vector<no_default> v1(10, init);//正确,提供了元素初始化器(执行结果是v1中有10个1) 15 // std::vector<no_default> v2(10);//错误,必须提供一个元素初始化器 16 return 0; 17 }
begin 和 end 成员:
1 #include <iostream> 2 #include <list> 3 using namespace std; 4 5 int main(void){ 6 list<string> a = {"Milton", "Shakespeare", "Austen"}; 7 auto it1 = a.begin(); //list<string>::iterator 8 auto it2 = a.rbegin();//list<string>::reverse_iterator 9 auto it3 = a.cbegin();//list<string>::const_iterator 10 auto it4 = a.crbegin();//list<string>::const_reverse_iterator 11 12 cout << *it1 << endl;//Milton 13 it1++; 14 cout << *it1 << endl;//Shakespeare 15 *it1 = "jflsfk"; 16 cout << *it1 << endl;//jflsfk 17 cout << endl; 18 19 cout << *it2 << endl;//Austen 20 it2++; 21 cout << *it2 << endl;//jflsfk 22 *it2 = "Shakespeare"; 23 cout << *it2 << endl;//Shakespeare 24 cout << endl; 25 26 cout << *it3 << endl;//Milton 27 it3++; 28 cout << *it3 << endl;//Shakespeare 29 // *it3 = "hello";//错误,常量迭代器类似于具有底层const的指针 30 cout << endl; 31 32 cout << *it4 << endl;//Austen 33 it4++; 34 cout << *it4 << endl;//Shakespeare 35 // *it4 = "hello";//错误,常量迭代器类似于具有底层const的指针 36 cout << endl; 37 38 const list<string> b = {"hello", "gg", "yy"}; 39 auto it5 = b.begin(); 40 auto it6 = b.rbegin(); 41 auto it7 = b.cbegin(); 42 auto it8 = b.crbegin(); 43 44 cout << *it5 << endl;//hello 45 it5++; 46 cout << *it5 << endl;//gg 47 // *it5 = "aa";//错误,const对象的begin()返回的是一个const_iterator 48 49 // b = a;//错误 50 51 list<string> const c = {"hello", "gg", "yy"};//可以将list<string>看作int,那么b和c分别相当于const int 和 int const,是等价的,都是顶层const 52 53 // c = a;//错误 54 55 return 0; 56 }
通过上面的列子还可以发现不以 c 开头的函数都是被重载过的。也就是说,实际上有两个名为 begin 的成员。一个是 const 成员,返回容器的 const_iterator 类型。另一个是非常量成员,返回容器的 iterator 类型。rbegin,end,rend 的情况类型。当我们对一个非常量成员调用这些成员时,返回的是 const 版本。只有在对一个 const 对象调用这些函数时,才会得到一个 const 版本。与 const 指针和引用类似,可以将一个普通的 iterator 转换成对应的 const_iterator,反之则不行。
而以 c 开头版本是 c++11 标准引入的,用以支持 auto 与 begin 和 end 函数结合使用。无论对常量容器还是非常量容器,其返回的都是 const_iterator。
即 auto 与 begin 或 end 结合时,获得的迭代器类型依赖于容器类型,而以 c 开头的版本是可以获得 const_iterator 的,无论容器的类型是否为 const。
将一个容器初始化为另一个容器的拷贝:
1 #include <iostream> 2 #include <list> 3 #include <vector> 4 #include <deque> 5 #include <forward_list> 6 using namespace std; 7 8 int main(void){ 9 list<string> authors = {"Milton", "Shakespeare", "Austen"};//列表初始化 10 vector<const char*> gel = {"a", "an", "the"};//列表初始化 11 12 list<string> list1(authors);//正确,类型都匹配 13 // deque<string> a(authors);//错误,容器类型不匹配 14 // vector<string> v(gel);//错误,元素类型不匹配 15 16 forward_list<string> f(gel.begin(), gel.end());//正确,只元素能相互转化即可 17 18 return 0; 19 }
为了创建一个容器为另一个容器的拷贝,两个容器的类型及其元素类型必须匹配。不过,当传递迭代器参数来拷贝一个范围时,就不要求容器类型是相同的了。而且,新容器和原容器中的元素也可以不同,只要能将拷贝的元素转换为要初始化的容器元素类型即可。
标准库 array:
1 #include <iostream> 2 #include <array> 3 using namespace std; 4 5 int main(void){ 6 array<int, 10> a;//类型为保存10个int的数组 7 array<string, 10> b;//类型为保存10个string的数组 8 9 array<int, 10>::size_type i;//数组类型包括元素类型和大小 10 // array<int>::size_type j;//错误,array<int>不是一个类型 11 12 array<int, 3> c = {1, 2, 3};//列表初始化 13 array<int, 5> d = {1};//d[0]为1,剩余元素都为0 14 //这两点和内置数组是一样的 15 16 int e[5] = {1, 2, 3, 4, 5}; 17 // int cpy[5] = e;//错误,内置数组不支持拷贝或赋值 18 array<int, 5> f = {1, 2, 3, 4, 5}; 19 array<int, 5> copy = f;//正确,只要数组类型匹配即合法 20 // copy = e;//错误,内置数组不能被赋值给array 21 // array<int, 4> g = f;//错误,数组大小不一致 22 23 return 0; 24 }
定义以及使用 array 类型时必须指定容器的元素类型和大小
数组类型包含元素的类型和大小,因此拷贝初始化时不仅要求初始值的类型必须与要创建的容器相同,大小也要相同
array 的列表初始化规则和内置数组一致
assign:
1 #include <iostream> 2 #include <list> 3 #include <vector> 4 using namespace std; 5 6 int main(void){ 7 list<string> names; 8 vector<const char*> old_style; 9 // names = old_style;//错误,容器类型不匹配不能赋值 10 names.assign(old_style.cbegin(), old_style.cend());//正确,可以将const char*转化成string 11 12 list<string> a(1);//一个元素,为空string 13 a.assign(10, "hello");//10个元素,每个都是hello 14 for(const auto indx : a){ 15 cout << indx << " "; 16 } 17 cout << endl; 18 19 a.clear(); 20 a.insert(a.begin(), 10, "hello");//通过输出可以发现这两条语句与前面的两条语句等效 21 for(const auto indx : a){ 22 cout << indx << " "; 23 } 24 cout << endl; 25 return 0; 26 }
赋值运算符要求左边和右边的运算对象具有相同的类型。此外顺序容器(array除外)还定义了一个名为 assign 的成员,允许我们从一个不同但相容的类型赋值,或从容器的一个子序列赋值。
需要注意的是:赋值相关运算会导致指向左边容器内部的迭代器、引用和指针失效。
swap:
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 int main(void){ 6 std::vector<string> v1(10, "f"); 7 std::vector<string> v2(24, "a"); 8 auto it = v1.begin();//此时it指向v1的第一个元素,是f 9 cout << &it << endl;//0x6afeb8 10 11 swap(v1, v2); 12 13 cout << *it << endl;//f 14 cout << &it << endl;//0x6afeb8 15 16 for(const auto indx : v1){//输出24个a 17 cout << indx << endl; 18 } 19 cout << endl; 20 for(const auto indx : v2){//输出10个f 21 cout << indx << endl; 22 } 23 return 0; 24 }
除 array 外,swap 不会对任何元素进行拷贝、删除或插入操作,因此可以保证在常数时间内完成。元素不会被移动也意味着,除 string 外,指向容器的迭代器、引用和指针在 swap 操作之后都不会失效。它们任指向 swap 操作之前所指向的那些元素,但是这些元素已经不属于原来的容器了。
insert:
注意:只有 vector、deque、list、string 支持 insert 成员
1 #include <iostream> 2 #include <list> 3 #include <vector> 4 using namespace std; 5 6 int main(void){ 7 vector<string> a; 8 list<string> b; 9 10 //在指定位置之前插入某个元素 11 b.insert(b.begin(), "hello");//等价于b.push_front("hello"); 12 a.insert(a.begin(), "hello");//vector不支持push_front,但我们通过insert达到了同样的效果 13 14 //在指定位置之前插入范围内元素 15 vector<string> v = {"kjf", "fksl", "fjsl", "fls"}; 16 b.insert(b.begin(), v.end() - 2, v.end());//将v中最后两个元素插入到b的开始位置 17 b.insert(b.end(), {"fjksl", "fskl", "fsl"});//在b的末尾插入一个列表 18 19 list<string> c; 20 auto it = c.begin(); 21 string s; 22 while(cin >> s){ 23 it = c.insert(it, s);//返回插入元素的迭代器 24 } 25 return 0; 26 }
需要注意的是:向一个 vector、string 或 deque 插入元素会使原来的迭代器、引用和指针失效。
emplace:
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 class gel{ 6 friend ostream& operator<<(ostream&, const gel&); 7 8 private: 9 int x, y, z; 10 11 public: 12 gel(int a, int b, int c) : x(a), y(b), z(c){} 13 ~gel(){} 14 }; 15 16 ostream& operator<<(ostream &os, const gel &it){ 17 os << it.x << " " << it.y << " " << it.z; 18 return os; 19 } 20 21 int main(void){ 22 vector<gel> a; 23 a.emplace_back(1, 2, 3);//隐式使用了构造函数 24 // a.push_back(1, 2, 3);//错误,没有接受3个参数的push_back版本 25 a.push_back(gel(2, 3, 4));//创建一个临时的gel对象传递给push_back 26 27 // a.emplace_back();//错误,gel类没有默认构造函数 28 a.emplace(a.begin(), 1, 2, 3);//将gel(1, 2, 3)插入到a的首元素前 29 30 for(const auto indx : a){ 31 cout << indx << endl; 32 } 33 return 0; 34 }
c++11标准引入了三个新成员——emplace_front、emplace 和 emplace_back,这些操作构造而不是拷贝元素。这些操作分别对应 push_back、insert 和 push_back。
注意:emplace 函数在容器中直接构造元素。传递给 emplace 函数的参数必须与元素类型的构造函数匹配。
访问元素:
c.back() 返回 c 中尾元素的引用(左值)。若 c 为空,函数行为未定义
c.front() 返回 c 中首元素的引用(左值)。若 c 为空,函数行为未定义
c[n] 返回 c 中下标为 n 的元素引用,n 是一个无符号整数
c.at(n) 返回下标为 n 的元素引用。如果下标越界,则抛出 out_of_range 异常
注意:at 和下标访问只适用于 string、vector、deque 和 array。back 不适用于 forward_list。
删除元素:
c.pop_back() 删除 c 中尾元素。若 c 为空,则函数的行为未定义。返回 void
c.pop_front() 删除 c 中首元素。若 c 为空,则函数的行为未定义。返回 void
c.erase(p) 删除迭代器 p 所指定的元素,返回一个指向被删元素之后元素的迭代器。若 p 是尾后迭代器,则行为未定义。
c.erase(b, e) 删除迭代器 b 和 e 之间所指定范围(左闭右开)内的元素。返回一个指向最后一个被删除元素之后元素的迭代器,若 e 本身就是尾后迭代器,则函数也返回尾后迭代器。
c.clear() 删除 c 中的所有元素。返回 void
注意:这些操作会改变容器的大小,所以不适用于 array。forward_list 有特殊版本的 erase。forward_list 不支持 pop_back。vector 和 string 不支持 pop_front。
删除 deque 中除首尾位置之外的任何元素都会使所有迭代器、引用和指针失效。指向 vector 或 string 中删除点之后位置的迭代器、引用和指针都会失效。
特殊的 forward_list 操作:
lst.before_begin() 返回指向链表首元素之前不存在的元素的迭代器。此迭代器不能解引用
lst.cbefore_begin() cbefore_begin() 返回一个 const_iterator,同样不能解引用
lst.insert_after(p, t) 在迭代器 p 之后的位置插入元素 t
lst.insert_after(p, n, t) 在迭代器 p 之后的位置插入 n 个元素 t
lst.insert_after(p, b, e) b 和 e 是一对范围迭代器(不能指向 lst 内),在迭代器 p 后插入迭代器 [b, e) 之间的元素
lst.insert_after(p, il) il 是一个花括号列表。返回一个指向最后一个插入元素的迭代器。如果范围为空,则返回 p。若 p 为尾后迭代器,则行为为定义
emplace_after(a, args) 使用 args 在 p 指定的位置之后创建一个元素。返回一个指向这个新元素的迭代器。若 p 为尾后迭代器,则行为未定义
lst.erase_after(p) 删除 p 指向的位置之后的元素,若 p 指向尾元素或者为尾后迭代器,则函数行为未定义。返回尾后迭代器
lst.erase_after(b, e) b, e 为一对范围迭代器,删除 [b, e) 之间的元素。返回一个指向被删元素之后的迭代器。若不存在这样的元素,则返回尾后迭代器
1 #include <iostream> 2 #include <forward_list> 3 using namespace std; 4 5 int main(void){ 6 forward_list<int> f = {1, 2, 3, 4, 4, 5, 6, 6, 7}; 7 auto a = f.before_begin(); 8 auto b = f.begin(); 9 f.insert_after(a, 100); 10 cout << *b << endl;//输出1,向链表中插入元素,原来的指针不会失效 11 12 auto c = f.begin(); 13 cout << *c << endl;//100 14 auto d = f.erase_after(c);//删除c之后的元素并返回删除元素之后的迭代器 15 cout << *d << endl;//2 16 17 for(const auto indx : f){ 18 cout << indx << " "; 19 } 20 cout << endl; 21 22 auto e = f.erase_after(f.begin(), ++(++f.begin())); 23 while(e != f.end()){ 24 cout << *e << " "; 25 e++; 26 } 27 cout << endl; 28 return 0; 29 }
改变容器大小(resize):
1 #include <iostream> 2 #include <list> 3 using namespace std; 4 5 class gel{ 6 private: 7 int x, y, z; 8 9 public: 10 gel(int a, int b, int c) : x(a), y(b), z(c){} 11 ~gel(){} 12 13 }; 14 15 int main(void){ 16 list<int> l(10, 1024); 17 l.resize(15);//将5个值为0的元素添加到l的末尾,此时l的大小为15 18 l.resize(25, -1);//将10个值为-1的元素添加到l的末尾,此时l的大小为25 19 l.resize(5);//从l的末尾删除20个元素,此时指向末尾20个元素的迭代器,指针和引用全部失效 20 21 list<gel> l2(10, gel(1, 2, 3)); 22 l2.resize(15, gel(1, 2, 3)); 23 // l2.resize(5);//错误,gel没有默认构造函数 24 return 0; 25 }
注意:array 不支持 resize
对于没有默认构造函数的数据类型不能使用一个参数版本的 resize
如果 resize 缩小容器,则指向被删除元素的迭代器、引用和指针都会失效
管理容量的成员函数:
c.shrink_to_fit() 将 capacity() 减少为与 size() 大小相同,即将多余的内存释放回系统
c.capacity() 返回 c 当前的容量大小
c.reserve(n) 分配至少能容纳 n 个元素的内存空间
其中:shrink_to_fit 只适用于 vector、string 和 deque
capacity 和 reserve 只适用于 vector 和 string
1 #include <iostream> 2 #include <list> 3 #include <vector> 4 using namespace std; 5 6 int main(void){ 7 vector<int> a(10, 2); 8 cout << a.size() << endl;//10 9 cout << a.capacity() << endl;//10 10 11 a.push_back(1); 12 cout << a.size() << endl;//11 13 cout << a.capacity() << endl;//20 14 cout << endl; 15 16 a.push_back(1); 17 cout << a.size() << endl;//12 18 cout << a.capacity() << endl;//20 size没有超过capacity时系统不会重新分配内存 19 20 for(int i = 1; i < 10; i++){ 21 a.push_back(i); 22 } 23 cout << a.size() << endl;//21 24 cout << a.capacity() << endl;//40 25 cout << endl; 26 27 for(int i = 0; i < 20; i++){ 28 a.push_back(i); 29 } 30 cout << a.size() << endl;//41 31 cout << a.capacity() << endl;//80 32 cout << endl; 33 34 //只有当前空间小于用reserve分配的空间大小时才会按照我们指定的大小重新分配内存空间 35 a.reserve(10); 36 cout << a.capacity() << endl;//80 37 a.reserve(100); 38 cout << a.capacity() << endl;//100 39 cout << endl; 40 41 //使用shrink_to_fit函数将多余的空间退回给系统 42 a.shrink_to_fit(); 43 cout << a.size() << endl;//41 44 cout << a.capacity() << endl;//41 45 return 0; 46 }
注意:重新分配内存时会引起迭代器、指针和引用失效
只有当需求的内存空间大于当前容量时,reserve 才会改变 vector 的容量大小
reserve 和 resize 的区别是 reserve 不改变容器中元素的数量,仅影响预先分配多大的内存空间,而 resize 恰好相反
构造 string 的方法:
string s(cp) 其中 cp 是一个 char* 字符,且其必须以空字符结尾
string s(cp, n) 此时 cp 不必以空字符结尾,但是 n 必须不大于 cp 的长度,否则该行为是未定义的
string s(cp + a, b) 从 cp[a] 开始拷贝 b 个字符构造 s,注意不能越界
string s(s2, pos) 从 s2[pos] 开发拷贝到 s2 结束,若 pos 大于 s2 的大小,则抛出一个 out_of_range 异常
string s(s2, pos, len) 从 s2[pos] 开始拷贝 len 个字符构造 s
1 #include <iostream> 2 using namespace std; 3 4 int main(void){ 5 const char *cp = "hello world!";//以空字符结束的数组 6 char a[] = {'H', 'i'};//不是以空字符结束 7 8 string s1(cp);//拷贝cp中的字符直到遇到空字符 9 cout << s1 << endl;//hello woeld! 10 cout << endl; 11 12 string s2(a);//未定义,a不是以空字符结尾 13 cout << s2 << endl;//乱码 14 cout.clear(ios::goodbit); 15 16 cout << endl; 17 string s3(a, 2);//从a[0]开始拷贝2个字符 18 cout << s3 << endl;//Hi 19 cout << endl; 20 21 string s4(cp + 6, 5);//从cp[6]开始拷贝5个字符 22 cout << s4 << endl;//world 23 cout << endl; 24 25 string s5(s1, 6, 5);//从s1[6]开始拷贝5个字符到s5中 26 cout << s5 << endl;//world 27 cout << endl; 28 29 string s6(s1, 0);//从s1[0]开始拷贝,直至s1末尾 30 cout << s6 << endl;//hello world! 31 cout << endl; 32 33 string s7(s1);//从s1[0]开始拷贝到s1末尾 34 cout << s7 << endl;//hello world! 35 cout << endl; 36 37 string s8(s1, 0, 100); 38 cout << s8 << endl;//hello world! 39 40 // string s9(s1, 100, 1);//抛出一个out_of_range异常 41 42 return 0; 43 }
substr 操作:
1 #include <iostream> 2 using namespace std; 3 4 int main(void){ 5 string s("hello world"); 6 string s1 = s.substr(0, 5);//从s[0]开始拷贝5个字符赋值给s1 7 cout << s1 << endl;//hello 8 cout << endl; 9 10 string s2 = s.substr(6);//从s[6]开始到s结束拷贝到s2 11 cout << s2 << endl;//world 12 cout << endl; 13 14 string s3 = s.substr(6, 11); 15 cout << s3 << endl;//world 16 17 // string s5 = s.substr(12);//抛出一个out_of_range异常 18 19 return 0; 20 }
改变 string 的其它方法:
s.insert(a, len, ch) 在 s[a] 之前插入 len 个 ch 字符
s.insert(a, s1) 在 s[a] 之前插入字符串 s1,s1 是一个 string 字符串
s.insert(a, s1, pos, len) 在 s[a] 之前插入字符串 s1 中从 s[pos] 开始的 len 个字符
s.erase(a, len) 删除从 s[a] 开始的 len 个字符
s.append(ch) 在 s 末尾追加一个字符 ch
s.replace(a, len, str) 删除从 s[a] 开始的 len 个字符然后再在此处插入字符串 str
1 #include <iostream> 2 using namespace std; 3 4 int main(void){ 5 string s; 6 s.insert(s.size(), 10, '!');//在s末尾插入10个感叹号 7 s.erase(s.size() - 5, 5);//从s删除最后5个字符 8 cout << s << endl;//!!!!! 9 cout << endl; 10 11 const char *cp = "abcdefg jfsljf fjs"; 12 s.assign(cp + 1, 8);//从cp[1]开始拷贝8个字符赋值给s 13 cout << s << endl;//bcdefg j 14 cout << endl; 15 16 string s1; 17 s1.insert(0, s);//在s1[0]之前插入s的拷贝 18 cout << s1 << endl;//bcdefg j 19 cout << endl; 20 21 s1.insert(0, s, 0, s.size());//在s1[0]之前插入s中s[0]开始的s0.size()个字符 22 cout << s1 << endl;//bcdefg jbcdefg j 23 cout << endl; 24 25 s.append("hello");//等价于 s.erase(s.size() - 5, 5) 26 cout << s << endl;//bcdefg jhello 27 28 s.replace(s.size() - 5, 5, "hello world!");//从s[s.size()-5]开始删除5个字符,然后再插入"hello world!" 29 cout << s << endl;//bcdefg jhello world! 30 31 return 0; 32 }
注意:字符数组越界问题
string 搜索操作:
搜索操作返回指定字符出现的下标,如果未找到则返回 npos(通常其值为-1,但是 npos 为 const string::size_type 类型(是 unsigned 的))
s.find(args) 查找 s 中 args 第一次出现的位置
s.rfind(args) 查找 s 中 args 最后一次出现的位置
s.find_first_of(args) 在 s 中查找 args 中任何一个字符第一次出现的位置
s.find_last_of(args) 在 s 中查找 args 中任何一个字符最后一次出现的位置
s.find_first_not_of(args) 在 s 中查找第一个不在 args 中的字符
s.find_last_not_of(args) 在 s 中查找最后一个不在 args 中的字符
其中 args 必须是以下形式之一:
c,pos 从 s 中位置 pos 开始查找字符 c。pos 默认为 0
s1, pos 从 s 中位置 pos 开始查找字符串 s1。pos 默认为 0
cp,pos 从 s 中位置 pos 开始查找指针 cp 指向的以空字符结尾的 c 风格字符串
cp,pos,n 从 s 中位置 pos 开始查找指针 cp 指向的数组的前 n 个字符。pos 和 n 无默认值
即共有 6 个不同的搜索函数,每个搜索函数又有 4 个重载版本
1 #include <iostream> 2 using namespace std; 3 4 int main(void){ 5 string name("AnnaBelle"); 6 auto pos1 = name.find("Anna"); 7 int pos4 = name.find("Anna", 1);//从name[1]开始查找Anna 8 cout << pos1 << endl;//0 9 cout << pos4 << endl;//-1 10 11 int pos2 = name.find("Cc"); 12 auto pos3 = name.find("Cc"); 13 cout << pos2 << endl;//-1 14 cout << pos3 << endl;//4294967295,find返回的是一个unsigned类型 15 16 string numbers("0123456789"); 17 string gel("jfs90fd00jf"); 18 cout << gel.find_first_of(numbers) << endl;//3 19 cout << gel.find_first_of(numbers, 4) << endl;//4 20 cout << gel.find_first_not_of(numbers, 4) << endl;//5 21 22 const char* ch = "cchhh"; 23 string cc("ch12"); 24 cout << cc.find(ch, 0) << endl;//4294967295 25 cout << cc.find(ch + 1, 0, 2) << endl;//0 从cc中0开始查找指针ch指向数组的前2个字符,即在cc中查找字符串"ch" 26 cout << cc.find_first_of(ch, 1, 3) << endl;//1 从cc中1开始查找指针ch指向数组的前3个字符中的字符第一次出现的位置 27 28 return 0; 29 }
compare 函数:
1 #include <iostream> 2 using namespace std; 3 4 int main(void){ 5 string s1("abc"); 6 string s2("abcd"); 7 int a = s1.compare(s2);//比较s1和s2 8 cout << a << endl;//-1 9 10 a = s1.compare(1, 2, s2);//将s1从s1[1]开始的两个字符和s2比较 11 cout << a << endl;//1 12 13 a = s1.compare(1, 2, s2, 1, 3);//将s1中从s1[1]开始的两个字符与s2中s2[1]开始的3个字符进行比较 14 cout << a << endl;//-1 15 16 const char *str = "abcd"; 17 a = s2.compare(str);//比较s1与空字符结尾的字符串数组的大小 18 cout << a << endl;//0 19 20 a = s2.compare(1, 3, str);//将s2中从s2[1]开始的3个字符与字符数组str比较 21 cout << a << endl;//1 22 23 a = s2.compare(1, 3, str + 1, 3);//将s2中从s2[1]开始的3个字符与指针str+1开始的3个字符开始比较 24 cout << a << endl;//0 25 26 return 0; 27 }
容器适配器:http://blog.csdn.net/selfi_xiaowen/article/details/49700539