欢迎光临散文网 会员登陆 & 注册

业余一下,浅显了解如何new一个数组,及其他相关的简单内容(?业余找喷(bushi

2023-08-05 00:18 作者:洛茨Deadcat  | 我要投稿

免责声明

反正也没人看本来没打算写,但还是套个盾)

因为浅显了解,所以文章语言浅薄片面。

因为本人也是新手,所以错误很多,欢迎指出。

因为第一次写稿,所以思路不清语言混乱。

因为是本人观点,所以不代表大众。

---------------------以下省略

此文章主要是面向跟我一样的新手或者非专业,没有经过系统化学,只想简单了解的人进行浅显补充。


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;

这个才是真的把数组本身的地址传给了指针。

输出结果:4*5

解引用之后的大小是一个完整的数组的大小。

且索引时需要先解引用再索引,即:(*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[]的类型。

业余一下,浅显了解如何new一个数组,及其他相关的简单内容(?业余找喷(bushi的评论 (共 条)

分享到微博请遵守国家法律