概要:数组是由一组同类型的元素组成的集合,在内存上是一片连续的存储空间。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的存储原理。

数组基础篇(对应C++ Primer plus 4.10)的更多相关文章

  1. 小猪猪C++笔记基础篇(四)数组、指针、vector、迭代器

    小猪猪C++笔记基础篇(四) 关键词:数组,Vector. 一.数组与指针 数组相信大家学过C语言或者其他的语言都不陌生,简单的就是同一个变量类型的一组数据.例如:int a[10],意思就是从a开始 ...

  2. 前端总结·基础篇·JS(二)数组深拷贝、去重以及字符串反序和数组(Array)

    目录 这是<前端总结·基础篇·JS>系列的第二篇,主要总结一下JS数组的使用.技巧以及常用方法. 一.数组使用 1.1 定义数组 1.2 使用数组 1.3 类型检测 二.常用技巧 2.1 ...

  3. Python学习笔记——基础篇【第五周】——算法(4*4的2维数组和冒泡排序)、时间复杂度

    目录 1.算法基础 2.冒泡排序 3.时间复杂度 (1)时间频度 (2)时间复杂度 4.指数时间 5.常数时间 6.对数时间 7.线性时间 1.算法基础  要求:生成一个4*4的2维数组并将其顺时针旋 ...

  4. 【Java 基础篇】【第二课】基本数组类型

    就像第一章所说一样,这次学习为了快,因此说明性的文字就不想写太多了,直接帖代码吧,代码当中尽量加一些注释: package a.b; public class test { static void B ...

  5. Java学习日记基础篇(七) —— 数组、排序

    数组 为什么要有数组? 案例:一个养鸡场有六只鸡,他们的体重分别为3kg,5kg,1kg,3.4kg,2kg,50kg.请问这六只鸡的总体重和平均体重是多少? public class test5 { ...

  6. iOS10 推送必看(基础篇)

    虽然这篇文章比较长,也不好理解,但是还是建议大家收藏,以后用到的时候,可以看看,有耐心的还是读一读. 这篇文章开始,我会跟大家好好讲讲,苹果新发布的iOS10的所有通知类. 一.创建本地通知事例详解: ...

  7. oracle(sql)基础篇系列(五)——PLSQL、游标、存储过程、触发器

      PL/SQL PL/SQL 简介 每一种数据库都有这样的一种语言,PL/SQL 是在Oracle里面的一种编程语言,在Oracle内部使用的编程语言.我们知道SQL语言是没有分支和循环的,而PL语 ...

  8. 一步步学习javascript基础篇(3):Object、Function等引用类型

    我们在<一步步学习javascript基础篇(1):基本概念>中简单的介绍了五种基本数据类型Undefined.Null.Boolean.Number和String.今天我们主要介绍下复杂 ...

  9. 《量化投资:以MATLAB为工具》连载(1)基础篇-N分钟学会MATLAB(上)

    http://blog.sina.com.cn/s/blog_4cf8aad30102uylf.html <量化投资:以MATLAB为工具>连载(1)基础篇-N分钟学会MATLAB(上) ...

随机推荐

  1. 搜索与图论①-深度优先搜索(DFS)

    深度优先搜索(DFS) 例题一(指数型枚举) 把 1∼n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序. 输入格式 一个整数 n. 输出格式 按照从小到大的顺序输出所有方案,每行 1 个. ...

  2. python黑帽子(第四章)

    Scapy窃取ftp登录账号密码 sniff函数的参数 filter 过滤规则,默认是嗅探所有数据包,具体过滤规则与wireshark相同. iface 参数设置嗅探器索要嗅探的网卡,默认对所有的网卡 ...

  3. Android四大组件——Activity——Activity数据回传

    既然可以传递数据给下一个Activity,自然也可以返回数据给上一个Activity.返回上一个Activity时只需要点击back键就好,并没有一个用于启动Activity的Intent来传递数据, ...

  4. stm32F103C8T6通过写寄存器点亮LED灯

    因为我写寄存器的操作不太熟练,所以最近腾出时间学习了一下怎么写寄存器,现在把我的经验贴出来,如有不足请指正 我使用的板子是stm32F103C8T6(也就是最常用的板子),现在要通过写GPIO的寄存器 ...

  5. 看完复旦博士用Python统计核酸结果后,我照着也写了一个

    前几天,人民日报公众号报道了复旦博士生自己写代码,通过OCR和正则表达式统计核酸截图结果.具体文章见:https://mp.weixin.qq.com/s/l8u9JifKDlRDoz32-jZWQg ...

  6. 企业实战|基于Cobbler实现多版本系统批量部署

    前言 运维自动化在生产环境中占据着举足轻重的地位,尤其是面对几百台,几千台甚至几万台的服务器时,仅仅是安装操作系统,如果不通过自动化来完成,根本是不可想象的.记得前面我们探究了基于PXE实现系统全自动 ...

  7. VUE3 之 Teleport - 这个系列的教程通俗易懂,适合新手

    1. 概述 老话说的好:宰相肚里能撑船,但凡成功的人,都有一种博大的胸怀. 言归正传,今天我们来聊聊 VUE 中 Teleport 的使用. 2. Teleport 2.1 遮罩效果的实现  < ...

  8. Web Api源码(路由注册)

    这篇文章只是我学习Web API框架的输出,学习方法还是输出倒逼输入比较行得通,所以不管写的好不好,坚持下去,肯定有收获.篇幅比较长,仔细思考阅读下来大约需要几分钟. 做.NET开发有好几年时间了,从 ...

  9. python 动态规划(背包问题和最长公共子串)

    背包问题 现在要往一个可以装4个单位重量的背包里怎么装价值最高:A重量1个单位,价值15:B重量3个单位,价值20:C重量4个重量,价值30 使用动态规划填充空格 class SolutionBag: ...

  10. linux篇-linux修改网卡名(亲测有效)

    1查看网卡ip addr 2cd /etc/sysconfig/network-scripts Ls查看 3mv ifcfg-eno16777736 ifcfg-eth0重命名,然后编辑 最后一行加入 ...