五、指针和数组
关于指针聊了这么久,接下去我们看看指针和数组之间有什么联系,如果想了解数组相关知识的,可以看看这篇文章——> 窥探数组设计的种种陷阱
我们看一个栗子🌰
- 在数组章节就有讲起过,数组名就是首元素地址,验证一下将它们的地址都打印出来可以发现是相同的
int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,0 }; printf("%p\n", arr); printf("%p\n", &arr[0]); return 0; }
- 因此我们就可以将数组名作为数组的首元素地址给到一个指针,通过这个指针就可以去遍历这个数组,因为
arr[i]
和*(p + i)
都可以访问到数组中下标为i这个元素,因此&arr[i]
和p + i
所访问的地址也是一样的
int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr; //指针存放数组首元素的地址 int sz = sizeof(arr) / sizeof(arr[0]); for (int i = 0; i < sz; i++) { printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i); } return 0; }
- 既然
&arr[i]
和p + i
所访问的地址也是一样的,那我们就可以通过*(p + i)
去访问这个数组中的所有元素
✒【总结一下】
- 数组和指针不是一个东西,数组能够存放一组数,是一个连续的空间,它的大小取决于
数组元素的类型和个数
;而指针则是用来存放地址,它的大小取决于你当前编译器所运行的环境
,是32位 / 64位 - 数组和指针的联系在于:数组名是首元素地址,把数组名给到一个指针变量之后,可以通过这个指针变量来访问这个数组中的所有元素
六、二级指针
好,看完了上面的这些内部,你对指针的一些基础算是入门了,接下去我们来做一些提升,学习一下二级指针🗡
1、变量、指针、二级指针
- 通过上面的学习可以知道,对于一个指针变量来说,可以接受一个变量的地址,那么这个指针其实就叫做【一级指针】,那我们知道对于一级指针来说也是有地址的,我也带你看过了,那现在我想做的一件事就是
把一个一级指针的地址存放到一个变量里
- 下面这个
pp
就是一个二级指针,它存放有一级指针p的地址
int a = 10; int* p = &a; int** pp = &p;
- 现在我通过下面这张图为你做一个讲解。首先变量a的值为10,地址为
0x00befd90
,然后一级指着变量p存放了变量a的地址,所以可以说它指向a。对于变量p来说,它也有自己的地址,为0x00befd84
,二级指针变量pp里则是存放了这个地址,所以可以说它指向p
- 然后来解释一下有关指针变量前面的一些星号:对于变量p,它前面的
*
表示它是一个指针变量,【int】则表示它保存的一个int
类型变量的地址,就说它指向一个整型变量 - 对于变量pp,它前面的
*
表示它是一个指针变量,【int *】则表示它保存的一个int*
类型变量的地址,就说它指向一个指针变量
👉万不可以把二级指针理解为就是前面两个星号这么简单,要将指针和地址之间的关系联系起来
肯定还有同学没有理解,我通过一个生活小案例来说明一下
- 其实【指针与地址】的关系就和【钥匙🔑与保险箱】的关系是一个道理,就比如说这个二级指针pp,它就是一把钥匙,它里面存放了一级指针p的地址,所以可以顺利地找p这个箱子,这样的话就可以通过这把钥匙打开这个箱子
- 但是这个箱子里面呢存有一把小钥匙,也就是一级指针p,它里面呢存放有变量a的地址,通过这把钥匙你就可以找到变量a,然后便可以通过新找到的这把钥匙打开变量a这个箱子,里面就有一个数值为10,它就是你要找的那个宝藏【看过极限挑战的读者应该都明白】
2、有关二级指针的运算
对二级指针有了一个初步的了解之后,我们来看看有关二级指针的一些运算
📚通过对二级指针进行一次解引用
,可以获取到一级指针变量,重新改变指向
📚通过对二级指针进行两次解引用
,可以获取到一级指针所存放的变量,重新改变值
- 看到下面这段代码,我新定义了一个变量b,然后可以看到通过
*pp
对二级指针进行了一个解引用的操作,这就获取到了一级指针变量p,此时我将变量b的地址存放到它里面去,这也就改变了指针p的指向
int a = 10; int b = 20; int* p = &a; int** pp = &p; *pp = &b;
- 我们可以通过DeBug调试来看看【上面是变化前,下面是变化后】
- 可以观测到,一级指针变量p存放的地址以及值都发生了改变,而且二级指针pp里所存放的一级指针变量p也发生了变化。这就是一次解引用可以实现的操作
接下去我们来看看通过两次解引用可以做到什么
- 看到如下代码,我通过两次解引用获取到了变量a的值,然后对其做了一个修改
int a = 10; int* p = &a; int** pp = &p; printf("a = %d\n", a); **pp = 200; printf("a = %d\n", a);
- 通过运行结果就可以看出a的值确实发生了变化,执行前和执行后的值有所不同
- 通过DeBug调试也是可以看出因为pp里面存放有p的地址,而p里面又存放有a的地址,我们可以将这个二次解引用做一个分解。第一次解引用首先找到一级指针p,然后再进行一个解引用便找到了变量a,此时就有了一个【修改的权限】
通过以上的叙述,相信你对二级指针有了一个初步的认识和理解,在之后的【指针进阶 · 提升篇】 中我还会再详解二级指针
这里补充一点,上面说到只要是指针均为4个字节,那对于二级指针来说呢?也是4个字节吗?
- 可以看到,的确如此,无论是一级指针还是二级指针,其大小并不取决于指针本身的类型,而是取决于当前这段代码所处的平台,在32为平台下均为4个字节,在64位平台下均为8个字节