前言:
之前的文章指针1和指针2,我们初步认识了指针,并了解了指针变量的大小,const修饰指针以及指针的三种运算,今天我们接着来讲指针的相关知识
1.数组名的理解
在指针2文章中我们提到数组名是一个地址,而且是数组首元素的地址,事实真的如此吗?我们来看下一段代码:
我们会发现arr[0]与arr的地址相同,这就验证了我们的猜想:数组名是数组首元素的地址。
有的小伙伴可能要问了,那有没有特殊情况?有两个特殊情况需要我们记住,分别是:sizeof(数组名)和&数组名
sizeof(数组名):
如果说数组名是首元素的地址的话,那么它的大小应该是4/8才对啊(地址大小在指针1讲过,忘记的小伙伴可以去复习一下),为什么结果却是40呢?这说明sizeof(数组名)是一个特殊情况;
&数组名:
这段代码三者运行结果相同,不是说&数组名是特殊情况吗?我们接着看下面一段代码:
结果又是如何呢?
从指针2我们明白了指针加整数会跳过相应的字节(char*为1个,int*为4个),故&arr[0]和&arr[0]+1相差4个字节,arr和arr+1相差4个字节。
但是&arr和?&arr+1相差40个字节,这就是因为&arr是数组的地址,+1操作是跳过整个数组的。
讲到这里我们就明白数组名的意义了:数组名表示数组首元素的地址,sizeof(数组名)和&数组名例外。
2.使⽤指针访问数组
有了前⾯知识的⽀持,再结合数组的特点,我们就可以很⽅便的使⽤指针访问数组了。
3.二级指针
我们通过前面的学习了解到指针变量是用来存放地址的变量,那么指针变量的地址在哪里存放呢?
答案是:二级指针
对二级指针解引用,即*ppa可以访问pa;对二级指针进行两次解引用,即**ppa就是访问a
4.指针数组
首先,我们要了解指针数组是什么,是指针还是数组?答案是数组,我们直接看末尾的部分:指针数组末尾是数组,所以它是数组。同理,数组指针就是一个指针。
指针数组的每个元素都是⽤来存放地址(指针)的。如下图所示:
4.1用指针数组模拟实现二维数组
对二维数组不了解的朋友可以去学习一下,其实二维数组的本质就是一维数组。我们这里讲如何通过指针数组模拟实现二维数组,老规矩先看代码:
这就是指针数组模拟实现二维数组的应用。
5.数组指针
我们已经明白了什么是指针数组,指针数组是⼀种数组,数组中存放的是地址(指针),那么数组指针是指针?还是数组?
答案是:指针。
我们已经熟悉:
• 整形指针变量: int * pint; 存放的是整形变量的地址,能够指向整形数据的指针。
• 浮点型指针变量: float * pf; 存放浮点型变量的地址,能够指向浮点型数据的指针。
那数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。
int*pa1[5];
int(*pa2)[5];
为了能让我们更好的区分指针数组和数组指针,我们来判断一下上面哪个是指针数组?哪个是数组指针?
答案:int*pa1[5]是指针数组;int(*pa2)[5]是数组指针;
那么如何理解数组指针呢?
5.1数组指针的初始化
之前我们学过&数组名能获得整个数组的地址,那么存放数组的地址,就用数组指针,如下:
究竟是不是这样呢,我们可以调试一下:
通过调试结果可知 &arr 和 p 的类型是完全⼀致的。数组指针的类型解析如下: