顺序容器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 }
View Code

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 }
View Code

通过上面的列子还可以发现不以 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 }
View Code

为了创建一个容器为另一个容器的拷贝,两个容器的类型及其元素类型必须匹配。不过,当传递迭代器参数来拷贝一个范围时,就不要求容器类型是相同的了。而且,新容器和原容器中的元素也可以不同,只要能将拷贝的元素转换为要初始化的容器元素类型即可。

标准库 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 }
View Code

定义以及使用 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 }
View Code

赋值运算符要求左边和右边的运算对象具有相同的类型。此外顺序容器(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 }
View Code

除 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 }
View Code

需要注意的是:向一个 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 }
View Code

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 }
View Code

改变容器大小(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 }
View Code

注意: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 }
View Code

注意:重新分配内存时会引起迭代器、指针和引用失效

只有当需求的内存空间大于当前容量时,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 }
View Code

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 }
View Code

改变 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 }
View Code

注意:字符数组越界问题

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 }
View Code

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 }
View Code

容器适配器:http://blog.csdn.net/selfi_xiaowen/article/details/49700539

原文地址:https://www.cnblogs.com/geloutingyu/p/8284527.html