1. ⼆级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪⾥?这就是 ⼆级指针 。
1.1 引入二级指针
由于一级指针已经很熟悉,这里就不再赘述,这里我们重点探讨二级指针
下面先简单使用一个二级指针看看
int main()
{
int a = 10;
int* pa = &a;
int** ppa = &pa;
return 0;
}
1.2 如何拆解二级指针类型
我们看到ppa的类型是 int** ,我们该如何理解指针的类型呢?
我们可以把两颗星号拆开来看
int* * ppa = &pa;
其中一颗 * 是在说明ppa是指针变量,⽽前⾯的 int* 是在说明pa指向的是整型指针(int*)类型的对象。
通过下图就更好理解:
int a = 10; 相当于向内存申请4个字节空间,这是变量a的空间,该空间对应一个内存的地址,它的地址假设为0x0012ff50,赋值为10,也就是将这个空间存放一个 10 。a的类型是整型。
int* pa = &a; 创建了一个指向整型的指针变量 pa,然后通过 &a 取出变量 a 的内存地址,取出的是第一个字节地址,也就是0x0012ff50,并将该地址赋值给指针变量 pa 。pa的类型是整型指针类型(int*)。另外指针变量也就是变量,也就是向内存申请了4个字节(32字节)或者8个字节(64位)空间,该空间对应一个内存的地.址,它的地址假设为0x0012ff48
而int** ppa = &pa; 则创建一个指向整型指针的指针变量 ppa,然后通过 &pa 取出指针变量 pa 的内存地址,取出的是第一个字节地址,也就是0x0012ff48,并将该地址赋值给指针变量 ppa 。pa的类型是整型指针的指针类型,也就是二级指针类型(int**)。
1.3 二级指针解引⽤
我们将地址保存起来,未来是要使⽤的,那怎么使⽤呢?
我们只要拿到了地址(指针),就可以使用解引用操作符(*)通过地址(指针)找到地址(指针)指向的对象。
*ppa 通过对ppa中的地址进⾏解引⽤,这样找到的是 pa , *ppa 其实访问的就是 pa .
int b = 20;
*ppa = &b;//等价于 pa = &b;
**ppa 先通过 *ppa 找到 pa ,然后对 pa 进⾏解引⽤操作: *pa ,那找到的是 a .
**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;
2. 指针数组
指针数组是指针还是数组?
我们类⽐⼀下,整型数组,是存放整型的数组,字符数组是存放字符的数组。
那指针数组呢?是存放指针的数组。
整型数组和字符数组
指针数组的每个元素都是⽤来存放地址(指针)的。
如下图:
指针数组的每个元素是地址,⼜可以指向⼀块区域。
3. 指针数组模拟⼆维数组
我们可以通过指针数组来模拟出二维数组。
#include <stdio.h>
int main()
{
int arr1[] = { 1,2,3,4,5 }; // 定义并初始化第一个整数数组 arr1
int arr2[] = { 2,3,4,5,6 }; // 定义并初始化第二个整数数组 arr2
int arr3[] = { 3,4,5,6,7 }; // 定义并初始化第三个整数数组 arr3
// 定义一个指针数组 parr ,其中每个元素都是指向整数的指针
// 并分别将 arr1、arr2、arr3 的地址赋给 parr 的元素
int* parr[3] = { arr1, arr2, arr3 };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++) // 外层循环控制遍历 parr 数组的元素
{
for (j = 0; j < 5; j++) // 内层循环控制打印每个数组的元素
{
printf("%d ", parr[i][j]); // 通过 parr[i] 可以得到对应的数组的地址,然后通过 [j] 来访问数组中的元素并打印
}
printf("\n"); // 换行,以便每个数组的打印结果分开显示
}
return 0;
}
模拟的是下图过程:
parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型⼀维数组,
parr[i][j]就是整型⼀维数组中的元素。
上述的代码模拟出⼆维数组的效果,实际上并⾮完全是⼆维数组,因为每⼀行并⾮是连续的。
本期博客介绍的二级指针、指针数组只是让同学们初步认识,
后面的指针学习章节我们更加深入的学习和使用,希望这几节指针的学习,不断提高自己的内功!
完