前言:
通过上一节的学习,我们已经对指针有了一定的了解,这一节,我们将更加深入地去了解指针的各个知识点。大家也可以按照下面的目录各取所需,希望看的每个人都有所收获。
目录
1.数组名的理解
让我们通过一段代码引入这节内容:
我们发现,当我们使用&arr[0]取到了数组的第一个元素的地址,且&arr取到的地址也是数组第一个元素的地址。其实数组名本来就是地址,而且是数组首元素的地址。
也就是说:
数组名就是数组首元素(第一个元素)的地址。
可要是这样的话,可能会与我们平时打的一些代码相违背,就像下面的例子:
上述列子中,我们创建了一个元素个数为6且类型为int的数组,我们在sizeof函数(sizeof函数是用于计算变量所占内存空间的大小,单位是字节)中输入数组名,如果按上文写的数组名ar是数组首元素的地址的话,那sizeof计算的便是首元素的地址,打印出的结果也应该是¥/8才对啊,难道我们先前学的知识出错了?其实不然:
数组名就是数组首元素(第一个元素)的地址是对的,但是有两个例外
- sizeof(数组名),sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组大小,单位是字节。
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)。
除此之外,任何地方使用数组名,数组名都是表示首元素的地址。
因此,我们上面代码中的打印是24是没错的,因为sizeof(arr)求的是整个数组的大小,数组中有6个元素,每个元素又是int型即4个字节,所以4*6=24,一切就合理起来了。
我们再接着下一组代码:
有敏感的同学可能已经发现了,arr + 1,跳过的是一个元素的大小;而&arr + 1跳过的是整个数组的大小。我们不禁会想,那arr和&arr有什么区别呢?
让我们看最后一组代码:
至此,我们可以得出结论:
&arr和arr的区别:
&arr[0]和&arr[0]+1相差4个字节,arr和arr+1相差4个字节,是因为&arr[0]和arr都是首元素地址,+1就是跳过一个元素
但是&arr和&arr+1相差40个字节,这就是因为&arr是数组的地址,+1操作是跳过整个数组。
2.使用指针访问数组
继续上代码:
在看到前两行代码大伙们可能还觉得合理,但后两行代码显然就有点反直觉了。但事实上就是:
p[i]本质上是等价于*(p + i )
i[arr] == *(i + arr) == arr[] == *(arr + i) == p[i]
数组元素的访问在编译期处理的时候,也是转换成成首元素的地址(arr)+偏移量(i)求出元素的地址,然后解引用(*)来访问的,即*(arr + i )。
- 数组就是数组,是一块连续的空间(数组的大小和数组元素个数和元素类型都有关系)
- 指针变量就是指针变量,是一个变量(4/8个字节)
- 数组名是地址,是首元素的地址
- 可以使用指针来访问数组
3.一维数组传参的本质
在平日里写代码的时候,我们有时需要计算一些位置数组的元素个数,有些同学棵能就会想着自己写一个求数组元素个数的函数,就像下面的函数test,但我们发现整个函数好像失灵了,这是为甚为什么呢?要解开这个疑问,我们就必须学习数组传参的本质了,我们通过上面数组名的理解的学习得知,数组名是首元素的地址,而我们在数组传参的时候传递的也是数组名,也就是说:本质上数组传参本质上传递的是数组首元素的地址。而这也是为什么上面的函数test的传参是用int* p接收。
所以我们可以得出结论:
- 数组传参的本质是传递了数组首元素的地址,所以形参访问数组和实参的数组是同个数组。
- 形参的数组是不会单独再创建数组空间的,所以形参的数组是可以忽略掉数组大小的
总结:一维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。
4.二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?我们还是通过指针来认识/
上图中ppa存放的地址是pa的地址,我们通过画图来滤清思路
就是二级指针
二级指针的运算
*ppa通过对ppa中地址进行解引用,这样找到的是pa。*ppa其实访问的就是pa
**ppa先通过*ppa找到pa,然后对pa进行解引用操作:*pa,那就找到的是a。
5.指针数组
指针数组是存放指针的数组。
指针数组的每个元素都是用来存放地址(指针)的。
指针数组的每个元素是地址,又可以指向一块区域。