C++随记(四)---动态数组vector

C++随记(四)---动态数组vector
前面两篇博文简单讲了一下C++通过new分配动态内存的问题。这一节就该轮到vector登场了,说实话我看完C++ Premier Plus的前半部分时(好吧说实话我是去年这个月就看了前半部分,今年这个月准备看完后面几章…也是浪的飞起,为了坚持看完,所以我才写了这些博文),最让我觉得很有意思,妙到可以拍手鼓掌的两个点:①模板类vector;②引用, 这两个东西简直让我服气啊,心里面在想:我靠,还有这种操作?
废话讲太多了,进入正题吧。
1、模板类vector;
vector 是一种动态数组,我们可以在运行阶段设置vector对象的长度!而常规数组是一开始就要把长度给定下来。而且vector还能在末尾附加新数据,还可以在中间插入新数据。基本上,它是使用new创建动态数组的替代品,而且它确实就是用new和delete来管理内存的,但是这种工作是自动完成的,所以你使用vector的时候完全就可以忘掉我前面两篇博文讲的东西,直接拿来vector用就ok了。 4个要点: ①使用vector对象时要包含头文件:#include<vector> ②vector包含在名称空间std中; ③使用时还是应该像数组那样指出它存储的数据类型; ④可以有很多方法来指定它的元素数。
我第一次见到vector是在使用Opencv的时候,经常看见用vector来装东西,对,我理解的就是vector就像一个篮子一样往里面塞东西就行了,这是我的第一印象。 经典的定义语句:
vector<数据类型> 对象名称 (元素个数)
①范例语句:
#include<vector>//这句话千万不要漏掉啊
using namespace std;
int n;
cin>>n;
vector<int> cars(n)
这就是一个典型的例子,这里我想说的,注意我的元素个数n是一个变量,是手动输入的。这就比起数组是一个伟大的进步啊!
你可以试试如果我把最后一行改成 int cars[n];是什么效果,编译器会报错的,告诉你那里不能用变量,因为数组定义的时候要确定元素个数!我觉得这其实是数组一个很过分的要求,我怎么能次次都做到知道需要多少个元素?我定义少了,运行时根本不够用,我定义多了,那不是浪费内存吗?
幸运的是,vector的出现改变了这一情况,我的n不但可以手动输入,而且这个n也可以是通过其他步骤计算出来的n,这就让我能够做到视情况而定嘛,多么nice!而且就算我是在定义的时候才导入了n,假设我的n此刻等于5,但是我后面完全可以增加,减少元素个数,可以让他长成10个元素,也可以让他缩成2个元素,是不是很方便。
②范例语句 事实上我在定义vector的时候完全可以空着元素个数那一个地方不写,
vector<int> cars;//这是合法的
这下我连n都不用考虑了,更nice了。
vector的基本操作: 以vector<int> cars; 为例
①向动态数组vector的末尾添加元素—push_back( ):
for( int a = 1; a++ ; a<=5){
cars.push_bcak( a );
此操作就是在每次循环时,往数组cars的屁股后面装入一个元素a.
②动态数组的长度—size( ):
由于我并未定义cars的长度,如果我现在需要用到它的长度该怎么半呢?cars.size( );
上面表达式的值就是数组的长度了,函数size( )返回的是容器中元素数目。
③动态数组的头—begin( ):
可以简单的理解为begin( )函数返回了数组第一个元素的地址(更精确的说法是返回了指向容器第一个元素的迭代器,可以理解迭代器为一个广义的指针)
cars.begin( );//就是我第一个元素cars[0]的地址了,注意也是从0开始算的
④动态数组的屁股—end( ):
end( )返回了指向容器尾部元素的迭代器,理解为最后一个元素的地址。
cars. end( );//就是我最后一个元素的地址,此例中就是cars[4]的地址。
⑤插入元素—insert( ):
既然是动态数组,那么除了我常用的从屁股后面按照顺序一个一个添加元素外,也可以在数组中间插入元素。
cars.insert( cars.begin( )+ i , b);在第i+1个元素前面插入b;
这里就用到了cars.begin( )作为第一个元素的地址。自然+i之后就是原来的第i+1个元素的位置插入新的元素。
⑥删除元素—erase( ):
能插入就能删除:
cars.erase ( cars.begin( )+ i);//删除第i+1个元素
⑦清空—clear( ):
如果觉得一个一个删除太麻烦了,我想把原来这个容器中的东西倒掉,重新装东西,那么:
cars.clear( );
基本的操作就是这些,平常应该够用了,这里要提到一个问题,既然是vector类是动态数组,那么我用平常普通数组的方式访问其元素是否可以呢?如 cars[2]是否合法?
回答是合法的,我们甚至可以直接对其值进行修改.如:
cars[2] = 100; 依然合法,这样的方式似乎合乎我们平时对于数组的概念
不过我更推荐使用成员函数.at()
cars.at(2) = 100;这种方式是比较安全的访问方式,这里不详细解释了。至于究竟想用哪个方式,取决于你的具体程序。
特别注意:如果要访问或者修改其中某个元素的值,一定要保证这个位置的元素已经被初始化了,也就是说原来这里有一个值。
我举个例子,比如我定义 vector<int> vec;
然后我想对其进行赋值,vec[2] = 100; 或者vec.at(2) = 100;
这样做程序会报错!!!会提示内存溢出!!vector subscript out of range!
因为一开始并没有说你容器vec究竟有多大,所以vec.at(2)这个位置并没有被分配内存!我们如果直接访问的话就自然有问题了,而push_back( )函数是一个一个的往后接龙,所以不会出现问题,所以要想直接对元素这么搞,必须要初始化vec。