业余一下,浅显了解如何new一个数组,及其他相关的简单内容(?业余找喷(bushi
免责声明
(反正也没人看本来没打算写,但还是套个盾)
因为浅显了解,所以文章语言浅薄片面。
因为本人也是新手,所以错误很多,欢迎指出。
因为第一次写稿,所以思路不清语言混乱。
因为是本人观点,所以不代表大众。
---------------------以下省略
此文章主要是面向跟我一样的新手或者非专业,没有经过系统化学,只想简单了解的人进行浅显补充。

new一个数组
如果你已经百度过了,应该已经知道了,所以直接上语法。
new T[]{};
new为关键词,T为数组的数据类型,[]内为数组元素个数,也就是数组长度,{}为c++11所加可以初始化数组的数据。
同new的其他对象一样,由于new返回的是一个适当类型的非零指针(或者可以理解为内存地址),可以拿一个适当类型的指针来接收返回数据:

祝:在有些文章里都会说,new的时候加了[]的,delete也都需要加[],即delete []p,但其实是不必要的。[]的作用只是调用每一个对象的析构函数,而对于简单的整数数组这种不需要调用析构函数的,有无[]都无妨。只有用到了析构函数的类才需要加[]。(但是当然,形成好的代码习惯应该是好的)例:



那么最经典的问题就来了:
指针指向的是数组哪里的地址?
"如果你已经百度过了",那么肯定知道指向数组的指针指向的是数组首元素地址。
那么什么是数组
那么因此可以直接进行以下的简单操作:

3个cout从上往下的操作依次是:
1.直接解引用指针ptr,因为指向的数组的首元素地址,所以解引用后的值是1,也就是第0位数。
2.返回ptr指向的地址的后一位地址(或者说首地址+1,因为数组是用一串连续的内存存储的),也就是数组的第1位数,也就是2。
3.++ptr是先将ptr指向的地址向后移动一位,也就是原本指向数组0的位置,现在指向了1的位置,所以输出值是2。
当然,也可以直接用下标运算符进行索引,例如ptr[3],返回的结果就是4。

数组
首先我们先简单声明一个名为arr的有3个元素的int类型的数组,并进行初始化:
int arr[3] = { 1,2,3 };
那么又来到了一个经典问题:数组名是不是一个指向首元素地址的指针。
(先打个甲,个人观点来说)数组名本身不是指针。尽管数组确实可以直接进行一些指针的操作:

在进行以上操作的时候arr确实变成了一个指向首元素地址的指针。这两个cout的输出结果也同上面的那个指针一样。
但是这只是表明在进行该运算的时候arr转变成了指针类型。
从比较直观的来看一下arr和ptr的区别。


对于输出arr和ptr的内存时,arr输出的是4*3,即含有3个int元素的数组的总内存。而ptr只是输出的指针本身的内存大小。且当arr前加运算符的时候,arr的内存转变为了8字节,也就是一个指针的大小。



用decltype()捕获数据类型时,对于ptr得到的是一个int的指针类型,对于整体的arr得到的是一个int[3]的数组类型。而当arr进行运算的时候arr隐式转换为了一个int*类型。
那么便得到了一个结论,也就是数组在进行运算的时候会隐式转化为指向首元素地址的指针,但是arr本身代表的是整个数组。
那么由此可得,为什么ptr直接指向一个数组的时候可以不需要取址符&:
int arr[5] = { 1,2,3,4,5 };
int* ptr = arr;
而实际上这个操作用指向数组这个说法是不准确的,它实际上不过是数组名先隐式转化为指向首元素地址的指针,然后把指针指向的值赋值给ptr。
int (*ptr)[5] = &arr;
这个才是真的把数组本身的地址传给了指针。


解引用之后的大小是一个完整的数组的大小。
且索引时需要先解引用再索引,即:(*ptr)[2]

最后补充几个细节:
1. &arr 和 arr 与 &arr + 1 和 arr + 1:


第一行是&arr 和 arr的地址
第一行是&arr + 1 和 arr + 1的地址
&arr取得是整个数组的地址也就是数组的首地址。
arr是直接先将arr转化为指针,然后输出了指针指向的地址,也就是数组的首元素地址。
从第一行可以看出来,首地址和首元素地址确实是相等的。
但当&arr + 1 和 arr + 1后地址变得不相同了。
因为arr+1根据上面所说只是首元素地址加一也就是数组中的下一个元素。
但&arr+1是整个数组的地址加一,等同于int a=1; &a+1; 用不准确的话来说,他是直接跳过了整个数组的地址指向了之后的数据,至于之后的数据是什么那就不知道了。
经过计算也可以得出:
C=12
000000B4830FFBDC-000000B4830FFBD8= 4 = sizeof(int) * 1(这里*是乘号)
000000B4830FFBDC-000000B4830FFBD8便于理解可以转化成10进制再算(只转换最后几位)
D=13 , E=14
16进制D8 = 十进制13*16^1+8*16^0 = 216 16进制E4 = 十进制14*16^1+4*16^0 = 228
228-216=16=sizeof(arr)=sizeof(int)*3
2.数组名隐式类型转换为指针类似于指针常量
这个其实没什么好说的,因为数组名转换为指针后,指针常指向数组的首元素地址,不可做为左值。
所以几乎等于指针常量


3.int* p[5] 和 int (*p)[5]
为什么上面 int (*ptr)[5] = &arr; 定义指向数组的指针时的定义方法是int (*p)[5]而不是int* p[5]
因为在c++中,[]的优先级高于*,int* p[5]=(int*)(p[])。就和int(arr[]),char(arr[]),甚至是class类 className(arr[])一样。他会先定义一个p的数组,然后再去确定数组存储的是什么数据,所以int* p[5]实际上是定义了一个长度为5的可以存储int*的数组。
而int (*p)[5]则是改变了优先级,先定义一个*p的不知道什么类型的指针,然后再去确定是一个int[]的类型。