vector类型与数组类型比较
- vector类型长度是动态的,可以根据需要动态的调用push_back函数添加新的元素,而数组的长度是固定的;
- 数组没有获取数组大小的函数,而vector类型提供size函数能够方便的获取容器的大小;
- 现代C++程序应尽量使用vector和迭代器类型,而避免使用低级的数组指针,只有在强调程序的速度时才在类实现的内部使用数组和指针。
一、vector类型(容器)
定义:
vector是同一种类型的对象的集合,标准库将负责管理与存储元素相关的内存,因为vector包含其他对象,所以也被叫做容器;
vector对象的定义与初始化:
4种初始化vector对象的方式
vector<T> v1;
vector<T> v2(v1);
vector<T> v3(n,i);
vector<T> v4(n);
vector对象值初始化:
在定义vector对象时,若没有指定元素的初始化式,那么标准库将自行根据存储在vector中元素的数据类型提供一个元素初始值进行值初始化
1.若vector存储的元素的数据类型为内置类型,那么标准库将用0值创建元素初始化式;
vector<int> fver(10);
2.若vector存储的元素的数据类型为类类型,那么标准库将自动调用该类类型的默认构造函数来创建元素初始化式
vector<string> svec(10);
3.若vector存储的元素的数据类型是没有定义任何构造函数的类类型,在这种情况下,标准库产生一个带初始值的对象,这个对象的每个成员进行了值初始化,而不是报错(error)
vector对象的操作
1.size操作
vector对象的成员函数size返回值为size_type,作用是返回vector对象的大小
2.vector对象的下标操作(访问操作)
vector对象是没用命名的,访问方式是通过vector中对象的位置来访问的,即通过使用下标操作符来获取元素
注:vector对象的下标操作并不能对vector对象进行添加元素操作,对vector对象进行添加元素的操作是用push_back操作来完成的;且vector对象的下标操作只能对已经存在的元素进行操作对于vector对象的访问操作有一种更有效的方式——使用迭代器(iterator)
注意:
1.vector是一个类模板,因此需要在使用之前,包含相应的头文件<vector>
2.在定义vector对象时,要指定类型和一个变量的列表
二、迭代器
定义:
迭代器是一种检查容器内元素并遍历元素的数据类型(一种类型支持一组确定的操作)
vector<int>::iterator iter;
注:可以这么理解,迭代器类似于指针
begin和end操作
每个容器都定了一对命名为begin和end的函数,用于返回迭代器,begin返回的迭代器指向vector的一个元素,而end返回的迭代器指向最后一个元素的下一个元素,他指向了一个不存在的元素,所以通常称为超出末端迭代器
vector迭代器的解引用操作符和自增自减操作符
迭代器可以使用解引用操作符(*操作符)来访问迭代器所指向的元素(这点与指针类似)
例:
*iter=0;
++iter;
*iter=1;
const_iterator与const iterator
使用const_iterator类型时,我们可以得到一个迭代器,该迭代器自身的值可以改变,但是它所指向的元素的值不能改变;
例:
for(vector<string>::const_iterator iter=text.begin();
在声明const iterator时,必须初始化迭代器,一旦被初始化之后,该迭代器的值就不能改变(因为该迭代器为常量)
vector<int> nums(10);
const vector<int>::iterator cit=nums.begin();
*cit=1;
++cit;
push_back()操作
vector对象的成员函数push_back操作将接受一个值,并将它作为一个新的元素追加到vector对象的后面
三、数组
数组是由类型名,标识符和维数的复合数据类型,数组的维数必须用值大于等于1的常量表达式定义(包含整形字面值常量、枚举常量、用常量表达式初始化的整型const对象)
数组的操作:
数组的操作是通过下标操作符来访问的,在用下标访问元素时,数组下标的类型为size_t与vector的迭代器类似,数组的遍历也可以用指针来实现指针
指针是指向某种类型对象的复合数据类型,是用于数组的迭代器,用于指向对象,保存一个对象的地址,因此,与迭代器不同的是:指针用于指向单个对象,并通过指针对其进行操作,而迭代器只能用于访问容器内的元素
四、指针
指针的取值
一个有效的指针必然是下面3种状态之一:保存一个特定对象的地址;指向某个对象后面的另一个对象;0值(不指向任何对象)。
指针初始化和赋值操作的约束
对指针进行初始化或赋值只能使用一下4种类型之一:0值常量表达式;类型匹配的对象的地址;另一对象之后的下一地址;同类型的另一个有效指针。(初始化或赋值时指针的类型一定要匹配)
例:
1)
int j=0;
const int i=0;
int *p1=0;
int *p2=j;
int *p3=i;
2)
double dval;
double *p1=&dval;
double *p2=p1;
int *p3=p1;
int *p4=&dval;
viod*指针
void*指针可以保存任何类型对象的地址,表明该指针与一地址值县官,但不清楚存储在此地址上的对象的类型;
void*指针只支持几种有限的操作与另一个指针进行比较;向函数传递void*指针或从函数返回void*指针;给另一个void*指针赋值;
注:不允许使用void*指针操纵它所指向的对象
指针与引用比较
1)引用总是指向某个对象,而且引用定义时就必须进行初始化
2)赋值行为的差异:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用重新与另一个对象关联,
引用一经初始化,就始终指向同一个特定对象;
指向指针的指针
指针本身也占用内存空间存放其值,因此,指针的存储地址也可以存放在指针中
例:
int val=1024;
int *pi=&val;
int **ppi=π
指针的算术操作
两个指针进行算术操作的返回值是ptrdiff_t类型,该类型也是一种与机器相关的类型,为signed整数
注:size_t可用来指明数组的长度,而ptrdiff_t类型则应保证足以存放同一数组中两个指针的距离,有可能是负数
在数组中,用下标对数组进行访问的实质是用下标访问指针对数组进行操作
例:
int *p=&a[2];
int j=p[1];
int k=p[-2];
指向const对象的指针、const指针和指向const对象的const指针
1)指向const对象的指针
不能修改指向const对象的指针所指向的内容,但可修改指针本身
例:
const double *cptr;
如果要用指针保存const对象的地址,只能用const指针来保存;也不能使用void*指针保存const对象的地址,只能用const viod*类型的指针保存const对象的地址;
指向const对象的指针可以保存非const对象(普通对象)的地址,但同样遵循不能通过修改该指向const对象的指针来修改非const对象的值的原则,但可以直接给该非const对象赋值或间接通过普通的非const指针修改该非const对象的值
2)const指针
指针本身的值不可修改,即一旦初始化,不可再指向其他对象,但可修改该指针所指向的对象的值
int numb=1;
int *const pnumb=&numb;
3)指向const对象的const指针
例:
const int i=22;
const int *const pi=&i;
即不能修改pi所指向的对象的值,又不能修改该指针的指向