8. 二级指针

二级指针就是指向指针的指针。

前面我们学习了指针,它是一个变量,它的内部保存的是所指向的变量的地址。那么有没有一个变量能够指向一个指针呢?答案就是二级指针。

在说二级指针之前我们先来说一下指针取地址运算符(&)。

当我们有个变量如下:

int x = 100;

变量 x 的类型是 int,当我们对变量 x 取地址时,表达式 &x 返回的值是一个数字代表内存地址,表达式返回的类型是 int*,我们为了保存这个 int* 类型的数值我们需要定义一个 int* 类型的指针。如下面代码所示。

int *px = &x;

现在我们程序中已经声明了两个变量 xpx。现在我们对变量 px 取地址,表达式 &px的返回值依旧是一个地址,但因为 px 的类型为 int*,当我们再次取地址为 &px时,要在 int*类型的基础上再加一个星号才是 &px 的类型,表示为 int**。我们要在程序中保存这个地址,需要定义一个 int** 类型的变量,这个变量就是二级指针。代码表示如下:

int ** ppx = &px;

变量 ppx 就是二级指针,它保存了 变量 px 的地址。

那么如何使用这个二级指针呢?答案是解引用。当对指针 ppx 一次解引用(*ppx)则得到的是它指向的变量 px ,如果对 *ppx 再次解引用(**ppx)则得到了 px 指向的变量 x。即:*ppx 为变量 px 的引用, **ppx 为变量 x 的引用。

让我们写一个完整可运行的示例来看一下吧。

// filename: pointer_to_pointer.c
#include <stdio.h>

int main(int argc, char *argv[]) {
    int x = 100;
    int *px = &x;
    int ** ppx = &px;

    // 打印三个变量的值
    printf("x:%d, px:%p, ppx:%p\n", x, px, ppx);

    // 打印三个变量的地址
    printf("&x:%p, &px:%p, &ppx:%p\n", &x, &px, &ppx);

    // 打印两个指针解引用后的值
    printf("*px:%d, *ppx:%p\n", *px, *ppx);

    // 打印指针ppx 二次解引用后的值
    printf("**ppx:%d\n", **ppx);

    return 0;
}

运行结果如下:

weimingze@mzstudio:~$ gcc -o pointer_to_pointer pointer_to_pointer.c
weimingze@mzstudio:~$ ./pointer_to_pointer
x:100, px:0x7ffe58bc0af4, ppx:0x7ffe58bc0af8
&x:0x7ffe58bc0af4, &px:0x7ffe58bc0af8, &ppx:0x7ffe58bc0b00
*px:100, *ppx:0x7ffe58bc0af4
**ppx:100

从上述运行结果可知 变量 px 保存的是 x 的地址, ppx 保存的是 px 的地址。 通过解引用运算符 *ppx 的值为 0x7ffe58bc0af4, 即 *ppx 就是 px 的引用。 **ppx 的值为 100, 即 **ppx 就是 x 的引用。

二级指针同一级指针一样遵循着指针的各种运算规则。

基于以上原理,同样还可以有三级指针、四级指针、…… 。只是我们很少使用罢了。

实验:

尝试使用二级指针对多个一级指针和多个变量进行操作。