文章目录

  • 数组基础概念
  • 数组的列表初始化
  • 数组的赋值和拷贝?×
  • 数组的维度
  • 字符数组
  • 复杂数组的解读
  • 数组和指针
  • 数组的遍历
  • 多维数组
  • 动态数组

数组基础概念

(1)数组大小固定。
(2)存放类型相同的对象的容器。定义数组的时候必须指定数组的类型,不允许使用 auto 关键字由初始值的列表推断类型。
(3)数组中元素的个数也属于数组类型的一部分,编译的时候维度应该是已知的。也就数说,维度必须是一个常量表达式
(4)数组的元素应该为对象,因此 不存在引用的数组
(5)在使用数组下标的时候,通常将其定义为 size_t类型。size_t是一种机器相关的无符号类型,它被设计的足够大以便能表示内存中任意对象的大小。
(6)通过数组名字和数组中首元素的地址都能得到指向首元素的指针。

//数组的初始化
#include <iostream>
using namespace std;int main(){const unsigned sz = 3;  int a1[3] = {0,1,2};           //含有3各元素的数组,元素分别是0,1,2 int a2[] = {0,1,2};              //维度是3的数组 int a3[5] = {0,1,2};         //等价于a3[] = {0,1,2,0,0} string a4[3] = {"i","and"};       //等价于a4[] = {"i","and",""} //int a5[2] = {0,1,2};           //错误:初始值太多。维度是2,但是初始化的变量是3,编译报错return 0;
}

数组的列表初始化

对数组进行列表初始化时,允许忽略数组的维度。因为如果在声明时没有指明维度,编译器会根据初始值的数量计算并推测出来。但是如果指明了维度,初始值的总数量不应该超出指定的大小,否则会编译报错

数组的赋值和拷贝?×

不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值
一些编译器支持数组的赋值,这就是所谓的编译器扩展。但一般来说,最好避免使用非标准特性,因为含有非标准特性的程序很可能在其他编译器上无法正常工作。

//不允许拷贝和赋值
#include <iostream>
using namespace std;int main()
{int a[] = {0,1,2};//int a2[] = a;        //错误:不允许使用一个数组初始化另一个数组 //a2 =a;         //错误:不能把一个数组直接赋值给另一个数组return 0;
}

数组的维度

数组中元素的个数,必须大于0,编译的时候维度应该是已知的,也就是说,维度必须是一个常量表达式

//数组的维度
#include <iostream>
using namespace std;int main()
{unsigned uint = 10;               //不是常量表达式constexpr unsigned cuint = 10;    //常量表达式 //string str[uint];             //编译报错:uint不是常量表达式string str[cuint];             //含有10个整数的数组 string *cstr[cunit];           //含有10个整型指针的数组return 0;
}

字符数组

字符数组有一种额外的初始化形式,可以通过字符串字面量对此类数组初始化 ,使用这种方式需要注意字符串字面值的结尾处还有一个空字符,这个空字符也会像字符串的其它字符一样被拷贝到字符数组中去。

//字符数组的初始化
#include <iostream>
using namespace std;int main(){char a1[] = { 'C' , '+', '+'};              // 维度:3,采取的列表初始化的方式,没有空字符char a2[] = { 'C', '+' , '+' ,'\0'};        // 维度:4,采取的列表初始化的方式,含有显式的空字符char a3[] = "C++";                          // 维度:4,采取字面量初始化的方式,字符串字面值末尾还有一个空字符。即自动添加表示字符串结束的空字符。//const char a4[5] = "Hello"; //错误。"Hello"看起来只有5个字符,但是数组大小必须是6,其中5个位置存放字面值的内容,另外一个存放结尾处的空字符 return 0;
}

复杂数组的解读

复杂数组定义的解读方法:由名字开始由内向外解读

//复杂数组的声明
#include <iostream>
using namespace std;int main()
{int *ptrs[10];         //含有10个整形指针的数组int arr[10];int (*parray)[10] = &arr;    //parray 指向 一个含有10个整数的数组 int (&arrRef)[10] = arr;  //arrRef 引用 一个含有10个整数的数组 int *(&array)[10] = ptrs;   //return 0;
}

(1)默认情况下,类型修饰符从右向左依次绑定,对于ptrs:首先我们定义的是一个大小为10的数组,它的名字是prts,然后知道数组中存放的是指向int的指针。
(2)但是对于parray来说,从左到右理解,即由内向外阅读就更合适。首先是圆括号括起来的部分,(*parray)意味着parray是一个指针,接下来观察右边(*parray)[10],可以知道parray是个指向大小为10的数组的指针,然后在观察左边,int (*parray)[10],知道数组的元素是int。这样就知道parray是一个指针,它指向一个int数组,数组中包含10个元素。
(3)int *(&array)[10] = ptrs; 首先知道array是个引用,然后观察右边知道引用的对象是一个大小为10的数组,然后观察左边,数组的元素是一个指向int的指针。这样,就得出了array就是一个含有10个int型指针的数组的引用。


数组和指针

(1)很多用数组名字的地方,编译器会自动地将其替换为一个指向数组首元素的指针
(2)指针加上一个整数得到的结果还是一个指针

#include <iostream>
using namespace std;int main(){string nums[] = {"i","love","you","haha"};string *p = &nums[0];       //p指向nums的第一个元素string *p2 = nums;          //等价于string *p2 = &nums[0] ,此时p2指向nums[0] ++p2;                       //此时p2指向nums[1]; string *last = &nums[4];  //得到数组尾元素之后那个并不存在的元素的地址。尾后指针不可以执行解引用和递增操作return 0;
}

数组作为一个auto变量的初始值时,推断得到的类型是指针而非数组。
但是当使用deltype关键字的时候,便不会发生上述转换。

int a[] = {0,1,2,3,4};
auto a2(a);                     // a2 是一个整型指针,指向a的第一个元素。等价于 auto a2(&a[0]),a2的类型是int *decltype(a) a3 = {0,1,2,3,4};  // a3 是一个含有10个整数的数组
a3[4] = 33;

指针也是迭代器。允许使用递增运算符将指向数组元素的指针向前移动到下一个位置上。

int a[] = {0,1,2,3,4};int *p = a;       // p 指向arr的第一个元素
++p;                // p 指向arr[1]int *p1 = a + 10;      // 错误写法:a只有5个元素,p1的值未定义。但是编译器无法发现错误
int *p2 = a + 5;      // 指向a的尾后指针,但不能解引用!

和迭代器一样,两个指针相减的结果是他们之间的距离。参与运算的两个指针必须指向同一个数组当中的元素。如果两个指针分别指向不相关的对象,则不能比较他们。
两个指针相减的类型是ptrdiff_t的标准库类型。和size_t一样,ptrsiff_t是定义在cstddef头文件中机器相关的类型。因为差值可能为负,所以ptrdiff_t是一种带符号类型

指针运算除了适用于指向数组的指针,还适用于空指针。后一种情况中,两个指针必须指向同一个对象后者该对象的下一个位置、
如果p是空指针,允许给p加上或减去一个值为0的整型常量表达式。两个空指针也允许彼此相减,结果是0。

int a[] = {0,1,2,3,4};auto n = end(a) - begin(a);     // n的值是4.也就是a中元素的数量

解引用与指针运算的交互:
虽然标准库类型string和vector也能执行下标运算,但是数组与他们还是不同的。标准库类型限定使用的下标必须是无符号类型,而内置的下标运算无此要求。内置的下标运算符可以处理负值,但是结果地址必须指向原来的指针所指向的同一个数组中的元素(或是同一数组尾元素的下一位置)。

#include <iostream>
#include <iterator>
using namespace std;int main()
{int a[] = {0,2,4,5,7,8};int s = *a;          //a[0]的值,即为0int s1 = *(a + 3); //a[4]的值,即为5int s2 = *a + 3;   //a[0] + 3的值,即为3int *p = &a[2];        //p指向索引为2的元素int val = p[1];        //p[1]等价于 *(p+1),也就是a[3]表示的那个元素 int val1 = p[-2];   //p[-2]等价于 *(p-2),也就是a[0]表示的那个元素 return 0;
}

数组的遍历

可以用尾后指针进行数组的遍历:

int a[] = {0,1,2,3,4};int *e = &a[5];    // e 指向arr尾元素的下一个位置的指针。尾后指针不指向具体的元素,不能解引用或递增操作// 可以使用尾后指针进行遍历
for(int *b = a; b != e; ++b)
{cout << *b << endl;
}

使用标准库函数 beginend 进行遍历:

#include <iostream>
#include <iterator>
using namespace std;
int main(){string nums[] = {"i","love","you"};//通过标准库函数begin和end遍历int *begin = begin(nums);     //指向nums首元素的指针 int *end = end(nums);           //指向nums尾元素的下一个位置的指针while(begin != end){cout << *begin << endl;++begin;} return 0;
}

多维数组

#include <iostream>
using namespace std;int main(){int a[3][4];         //大小为3的数组。每个元素是含有4个整数的数组 int (*p)[4] = a;      //p指向含有4个整数的数组 for(auto &row:a){for(auto &col:row){cout << *col << " ";}cout << endl;}for (int (*p)[4] = begin(a);p != end(a);p++){for (int *q = begin(*p);q != end(*p); q++){cout << *q <<endl;}}return 0;
}

动态数组

new和delete运算符都是一次分配/释放一个对象。
但是像vector和string都是在连续内存中保存它们的元素,因此,当容器需要重新分配内存时,必须一次性为很多元素分配内存。

通过new来分配一个对象数组
分配一个数组会得到一个元素类型的指针***。虽然我们称new T[]分配的内存为“动态数组”,当用new分配一个数组时,我们并未得到一个数组类型的对象,而是得到一个数组元素类型的指针*。由于分配的内存并不是一个数组类型,因此不能对动态数组调用begin或end。也不能用for语句来处理动态数组中的元素。

#include <iostream>
#include <list>
using namespace std;int main(){int *pa = new int[10];              //10个未初始化的int ,pa指向第一个int元素int *pa2 = new int[10]();           //10个值初始化为0的intint *pa3 = new int[10]{0,1,2,3,4,5,6,7,8,9};    //使用初始化器初始化 string *spa = new string[10];      //10个空string string *spa2 = new string[10]();  //10个空stringstring *spa3 = new string[10]{"a","b","c",string(3,'x')};  //前四个使用初始化器初始化,后面的就默认进行值初始化 return 0;
}

释放动态数组
通过delete []a,销毁a指向的数组中的元素,并释放对应的内存。数组中的元素按照逆序进行销毁。

C++ 数组、数组指针、指针数组、动态数组等详解相关推荐

  1. C++中数组和指针的关系(区别)详解

    C++中数组和指针的关系(区别)详解 本文转自:http://c.biancheng.net/view/1472.html 博主在阅读后将文中几个知识点提出来放在前面: 没有方括号和下标的数组名称实际 ...

  2. php 合并数组对象,JS内数组合并方法与对象合并实现步骤详解

    这次给大家带来JS内数组合并方法与对象合并实现步骤详解,JS内数组合并方法与对象合并实现的注意事项有哪些,下面就是实战案例,一起来看一下. 1 数组合并 1.1 concat 方法var a=[1,2 ...

  3. C语言结构体与指针ppt,c语言指针和结构体:链表详解.ppt

    c语言指针和结构体:链表详解.ppt 1,第十一章 链表,2,例跳马.依下图将每一步跳马之后的位置x,y放到一个"结点"里,再用"链子穿起来",形成一条链,相邻 ...

  4. VB静态调用与动态调用dll详解

    [[请注意]]:在以下语法格式中,请注意 [函数名] 的[大小写]!!! 静态与动态比较: 静态调用简单,动态调用麻烦:静态调用占用资源多,动态调用占用资源少:正所谓鱼和熊掌不可兼得. 静态调用定义: ...

  5. linux动态库注册函数,Linux动态库函数的详解

    linux动态库函数的详解 加载动态库 void *dlopen(const char *filename, int flag); flag的可能值: rtld_lazy rtld_now rtld_ ...

  6. 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

    2019独角兽企业重金招聘Python工程师标准>>> 在运行时期可以按照Java虚拟机规范对class文件的组织规则生成对应的二进制字节码.当前有很多开源框架可以完成这些功能,如A ...

  7. java的动态代理机制详解

    2019独角兽企业重金招聘Python工程师标准>>> 参考资料 1.java的动态代理机制详解 转载于:https://my.oschina.net/Howard2016/blog ...

  8. C-指针,二级指针,二维数组作为函数参数使用,C语言链表(详解)

    一级指针 int *p;            //表示定义一个int型(4字节)的指针p &p                 //表示p自身的地址位置 p                  ...

  9. php动态写入vue,Vue自定义动态组件使用详解

    这次给大家带来Vue自定义动态组件使用详解,Vue自定义动态组件的注意事项有哪些,下面就是实战案例,一起来看一下. 现在基于vue的UI组件库有很多,比如iview,element-ui等.但有时候这 ...

  10. linux mysql 静态库_Linux静态库与动态库实例详解

    Linux静态库与动态库实例详解 1. Linux 下静态链接库编译与使用 首先编写如下代码: // main.c #include "test.h" int main(){ te ...

最新文章

  1. VS Code 安装 Go 插件、自定义扩展配置、断点调试
  2. 进军ABP第一天:ABP理论知识
  3. Spring boot 梳理 - WebMvcConfigurer接口 使用案例
  4. java 贝塞尔_java贝塞尔曲线翻页效果
  5. 5分绩点转4分_作为一名大学生,如何规划4年大学生活?学姐:建议从这5点做起...
  6. 用计算机做科学计算是绝对精确的吗,科学计算与数学建模 - osc_3gfjojb2的个人空间 - OSCHINA - 中文开源技术交流社区...
  7. xtext_使用Xtext为Eclipse和IntelliJ开发DSL
  8. OpenCV_11 轮廓检测:图像的轮廓+绘制轮廓+轮廓近似+边界矩形+椭圆拟合+直线拟合
  9. Ajax(一)——Ajax基础概念,HTTP头部(重点)
  10. java常用的搜索引擎_我掏空了各大搜索引擎,给你整理了154道Java面试题!
  11. explain的用法_这次是真拯救了我,MySQL索引优化,explain讲得非常清楚了
  12. 物联网技术或颠覆传统高等教育
  13. 深圳电大计算机等级考试报名时间2015,杭州2015下半年计算机等级考试报名
  14. autowired注解_Spring系列之Spring常用注解总结
  15. HDU 1394 Minimum Inversion Number 树状数组
  16. 全球与中国调频广播发射机市场深度研究分析报告
  17. IDEA 安装插件后,重启插件消失问题
  18. linux tomcat startup.sh,Tomcat 安装教程与启动-startup.sh
  19. (Emitted value instead of an instance of Error) Do not use v-for index as key on <transition-group>
  20. Git基本命令及缩写

热门文章

  1. hadoop fs –ls /hbase 无内容_Hadoop学习---HDFS的常用shell命令详解
  2. 盛迈坤电商:直通车的优化操作技巧
  3. Android 4学习(8):用户界面 - Fragment
  4. Adobe 数字出版解决方案 Digital Publishing Suite (Indesign 制作iPad电子书) 系列之一: 环境准备
  5. 抢跑Serverless DB,腾讯云打的什么算盘?
  6. 鱼眼相机相关知识及其标定矫正
  7. Android 使用CameraX拍照、预览
  8. linux 文件 跳板机_转载 linux 基于ssh创建跳板机
  9. React项目搭建步骤
  10. 华为nova5i计算机在哪,IT教程:华为nova5与nova5i的区别