数组基础篇(对应C++ Primer plus 4.10)

概要:数组是由一组同类型的元素组成的集合,在内存上是一片连续的存储空间。C++提供了三种数组的表示方法:普通数组模板类vector(C++98 新增的标准模板库STL提供该模板类)和模板类array(C++11新增)

下面分别讨论这三种类型的数组是如何使用的以及他们的区别:

一,这三种数组如何被定义?初始化?元素如何被访问?

(1)普通数组

 普通数组定义和初始化:

    typename vt[n_elem];      //数组vt长度n_elem必须是定常量或常量表达式

         int a1[10]={1,3,4};  //定义由10个int型变量的数组a1,并用列表中数值依次对数组元素进行初始化(不足项默认为0)

        int a1[]={1,3,4};     //定义由3个int型变量的数组a1,(这里定义数组时长度可以省略)

        char a1[]="i i"       //定义由4个char型变量组成的数组a1(注意别忘了字符串中间的空格和字符串结尾省略的空字符,另外中文字符占2字节,英文、空格、结尾空字符都占一个字节)

 普通数组元素的访问:

         int a1[3]={1,3,4}; 

         cout<<a1[2]<<*(a1+2)<<endl;    //可以通过数组名和元素下标来访问数组的元素;a1[2]相当于*(a1+2),数组名a1被解析为第一个元素的地址,这里即引用第一个元素往后移动两个元素位置的地址上数值。

         int p1=a1;                                  //使用指针指向数组首地址后即可像数组名那样访问数组元素(而且是引用不是copy),

         cout<<p1[2]<<endl;                  //p1[2]相当于a1[2],  即p1[2]---a1[2]---*(p1+2)---*(a1+2)

         int p2=&a1[1];

        cout<<p2[1]<<*(p2+1)<<*(a1+1+1)<<a1[2]<<end;           //这三者等

(2)模板类vector(动态数组)

模板类vectot的定义和初始化:

vector<typename>vt(n_elem);  //注意,vector对象vt的长度n_elem可以是常量也可以是变量;在运行阶段根据实际需要设置它的长度;

#include<vector>

...

using name space std;

//

vector<int> a2;     创建由0个int型变量组成的vector对象,内存为0;

a2.push_back(0)

a2.push_back(1)       //.push_back为vector模板类的一个方法,用于给数组扩容,即往数组尾部插入变量;注意,这里不能用a2[i]=数值;否则因vector数值越界而程序中断;

a2.push_back(2)     //vector对象的存储空间每次扩大时都会重新申请一片空间,然后将旧空间存储的值copy过来,最后将就空间释放;所以vector功能虽强,但代价是效率低。

//

vector<int>a2(10); //创建由10个int变量组成的vector对象;

a[0]=0;

...

a[9]=9;     //注意,C++98不支持用列表初始化vector对象,仅普通数组和array对象支持列表初始化;但在C++11新增了vector的列表初始化;

 

模板类vectot对象的元素访问:

同上面普通数组,可用vector对象名和元素下标访问a2[i],也可以用指向vector对象的指针访问 ;注意区别在于vector对象名不能被解析为第一个元素的地址。

    int n;
    cin >>n;
    vector<int>a2(n);
    a2[2] = 2;
    int* p = &a2[0];
    cout << a2[2] << p[2] << *(p + 2);       //这三者等效

*遗留问题1:vector对象内存空间如何缩小?具体的原理是什么?

 

(3)模板类array

模板类array的定义和初始化

  array<typename,n_elem>vt;      //同普通数组一样,创建array对象必须指定长度,n_elem须是常量或常量表达式。

  #include<array>

  ...

  using name space std;

  array<int ,3>a3={1,2,3}   //定义由三个int型变量组成的array对象,并用列表里数值对array对象的元素进行初始化。

 

模板类array对象的元素访问:

     对array对象的元素进行访问时,同普通数组和vector对象一样,都能通过对象名和元素下标进行访问,或者用指向对象的指针进行访问,

     但同样,array对象名和vector对象名一样,不能像普通数组名称那样被解析为首元素的地址,即&a2[0]不等同于a2,&a3[0]不等同于a[3]

     示例如下:

    array<int, 3>a3 = { 1,2,3 };
    int* p = &a3[0];
    cout << a3[2] <<p[2]<<*(p+2) << endl;

 

二,三种数组的比较

     1-就灵活性和功能上来说,模板类vecotor具有更高的灵活性,体现在其定义时不用指定具体的长度,而是可以在程序运行时根据需要确定其长度大小,另外,当vector对象的存储空间不够用时,会自动扩容,而无需手动分配内存。

    2-就效率而言,由于vector对象每次扩容时都会重新申请一片更大的内存空间,然后将数据从原来的存储空间copy过来,再释放原来的存储空间;这样的过程将大大降低效率;而普通数组与array对象都是长度固定的,也使用栈(静态内存分配),而不是自由存储区,因此二者效率一样,都比vector高效。

    3-安全性上:C++/C不会检查数组越界的情况,如a1[-2]=3,而array和vector提供了检查数组越界的方法.at(),使用at(i)访问元素时,会先判断小标i是否合法,从而提高了安全性。

   4-方便性,vector和array对象可以进行赋值操作,而内置数组只能逐个元素copy,另外,vector和array有很多方便的api 如获取长度.size(),判断是都为空.empty(),而数组只能通过sizeof() / strlen()以及遍历计数来获取大小和是否为空。

   5.vector和array提供了更好的遍历机制,即有正向迭代器和反向迭代器
   6.vector和array提供了两个容器对象的内容交换,即swap()的机制,而数组对于交换只能通过遍历的方式逐个交换元素
   7.array提供了初始化所有成员的方法fill()
   8.由于vector的动态内存变化的机制,在插入和删除时,需要考虑迭代的是否有效问题
   9.vector和array在声明变量后,在声明周期完成后,会自动地释放其所占用的内存。对于数组如果用new[] / malloc申请的空间,必须用对应的delete[]和free来释放内存

   10.array对象和数组存储在相同的内存区域(栈)中,vector对象存储在自由存储区(堆)。

 

------------总结

通过以上比较,以后如需动态数组,使用vector,如需固定长度数组,选用array.

另外,学习栈和堆后回顾一下array和内置数组、vector的存储原理。

posted @   newloser  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示