下半部分主要介绍迭代器和数组部分。
迭代器
迭代器类似于指针,可以间接访问对象。
迭代器的使用
迭代器拥有begin和end成员,begin是负责指向第一个元素的迭代器,end是指向一个容器根本不存在的“尾后”,begin和end成员返回的迭代器是同一个迭代器称为尾后迭代器。
标准容器迭代器的运算符
*iter 返回迭代器iter所指向元素的引用
iter->men 解引用iter并获取该元素名为men的成员,等价于(*iter).men,注意圆括号不能少。
++iter 令iter指向容器的下一个元素
--iter 令iter指向容器的上一个元素
iter1==iter2 判断两个迭代器是否相等
iter1!=iter2
在C++11中引入两个新的函数分别是cbegin和cend,这两个函数和原本的begin和end的区别是,无论对象(vector或string或其他)本身是否是常量,返回来的值都是常量类型。
迭代器的运算
iter+n 迭代器加上一个整数值仍是一个迭代器,迭代器的新位置与原来相比向前移动若干个元素。结果迭代器或者指示容器内的一个元素,或者指示容器尾元素的下一个位置
iter-n 和上面含义类似
iter+=n 将iter加n的结果返回给iter
iter-=n 和上面的含义类似
iter1-iter2 两个迭代器直接的距离
3.21 输入一组整数,使用迭代器输出vector容器的内容
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int main()
{
vector<string> v7{10,"hi"};
for(auto a=v7.cbegin();a!=v7.cend()&&!a->empty();a++)
cout<<*a<<" "; //*解引用
}
3.23 输入一组数字,输出数字的两倍
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v;
int temp;
cout<<"please input ten characters:"<<endl;
for(int i=0;i<10;i++)
{
while(cin>>temp)
v.push_back(temp);
}
for(auto it=v.begin();it != v.end();it++)
cout<<*it*2<<" ";
}
3.24 读入一组整数,使第一个数组加最后一个数字,第二个数字加上倒数第二个数字以此类推,最后输出结果
// 迭代器没有加法,只有减法,减法是距离含义
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> vInt;
cout<<"Please input charaters"<<endl;
int i;
while(cin>>i)
vInt.push_back(i);
if(vInt.begin()==vInt.end())
{
cout<<"empty"<<endl;
return -1;
}
auto beg=vInt.begin();
auto end=vInt.end();
for(auto it=beg;it!=beg+(end-beg)/2;it++)
cout<<*it+*(beg+(end-it)-1)<<" ";
if(vInt.size()/2!=0) //如果是奇数 单独处理中间的数字
cout<<*(beg+(end-beg)/2);//先计算出从头到尾的元素个数,然后控制迭代器从开始向右移动1/2个元素定位到中间
}
在这道题中我们使用了一个算法,二分搜索。里面有个小细节二分搜索使用的mid=(beg+end)/2,但是程序里却是mid=beg+(end-beg)/2。为什么要这么写呢?
是因为C++没有两个迭代器的加法运算,实际上把两个迭代器相加也是没有意义的。但是迭代器有减法运算,相减的结果是他们的距离所以mid=(beg+end)/2是不合法的,mid=beg+(end-beg)/2的含义是先计算end和beg直接的距离,也就是容器元素个数的值,然后从迭代器开始时向右移动距离的二分之一,到中间位置。
数组
数组也是存放类型相同对象的容器,这些对象本身没有名字,需要通过其所在位置访问。与vector不同的地方是,数组的大小确定不变,不能随意向数组中增加元素。
数组的声明
a[b]
其中a是数组的名字,b是数组的维度,维度说明了数组中元素的个数,因此必须大于0。
数组如何初始化
注:不存在引用的数组,但是存在数组的引用。
int &refs[10]=/*?*/ 错误 这是引用的数组
int (&refs)[10]=arr; 正确 数组的引用,引用一个含有10个整数的数组
3.31 创建一个数组,令其每个元素的值就是其下标的值
#include<iostream>
using namespace std;
int main()
{
int a[10];
for(int i=0;i<10;i++)
a[i]=i;
for(int j=0;j<10;j++)
cout<<a[j]<<" ";
cout<<endl;
}
3.32 将上题中的数组拷贝给另一个数组
#include<iostream>
using namespace std;
int main()
{
int a[10],b[10];
for(int i=0;i<10;i++)
{
a[i]=i;
b[i]=a[i];
}
for(int j=0;j<10;j++)
cout<<b[j]<<" ";
cout<<endl;
}
用vector实现
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> a,b;
for(int i=0;i<10;i++)
{
a.push_back(i);
}
for(int i=0;i<10;i++)
{
b.push_back(a[i]);
}
for(auto &i:b)
cout<<i<<" ";
cout << endl;
return 0;
}
指针和数组
在使用数组时,编译器会把它转化成指针。对数组使用取地址符可以获得指向该元素的指针:
string *p=&num[0];
使用数组名的地方,编译器会自动将其替换为一个指向数组首地址的指针
string *p2=num;//等价p2=&nums[0]
auto ia2(num); //ia2是一个string型指针,指向num的第一个元素
指针也是迭代器。为了让指针使用起来更安全C++11引入两个名为begin和end的函数
int a[]={1,2,3,4};
int *beg=begin(a); //指向首地址
int *last=end(a); //指向尾元素的下一个地址
主要尾指针不参与解引用和递增操作
指针的运算和迭代器完全一致,具体使用方法可以参考上面迭代器。
解引用与指针
指针加上一个整数所得的结果还是一个指针。假设结果指针指向一个元素,则允许解引用该结果指针:
int a[]={1,2,3,4};
int last=*(a+2);
表达式*(a+2)计算a向前2个元素后的新地址,解引用是取里面的内容,相当于a[2];
下标和指针
指针指向的是数组中的元素都可以执行下标运算:
int *p=&a[2]; //p指向索引为2的元素
int j=p[1]; //p[1]等价于*(p+1),就是a[3]表示的那个元素
int k=p[-2]; //p[-2]表示a[0]表示的那个元素
3.35 编写一段程序用指针将数组里的值全部置零
#include<iostream>
using namespace std;
int main()
{
const int sz=100;
int a[sz],*p;
cout<<"The original number is"<<endl;
for(int i=0;i<sz;i++)
{
a[i]=rand()%100;
cout<<a[i]<<" ";
}
p=begin(a);
while(p !=end(a))
{
*p=0;
p++;
}
cout<<endl<<"The revised content is" <<endl;
for(auto &i:a)
{
cout<<i<<" ";
}
return 0;
}
C风格字符串
不建议使用