int*int 说起

int**是什么” 这个问题其实不难。
我们可以递归分析,先看下 int*是什么,嗯?好像还可以继续递归到 int
我们都知道,int是 C 的基础数据类型 整型,而多了个 *int*指向整型变量的指针,那么 int** 是什么就不言自明了,列个表:

C语法释义
int整型
int*指向整型的指针
int**指向指向整型的指针的指针

看到这里,你对 int** 应该有了个初步的认识,但你可能觉得有点绕,没关系,下面我们写一段代码看看:

#include <stdio.h>

int main()
{
    int i = 418;

    int* pi;
    // 根据上面的表格,我们知道 int* 是指向“整型”的指针,
    // 那么 pi 可以保存的是 int 类型的变量 i 的地址:
    pi = &i;

    int** ppi;
    // ppi 可以保存的是 int* 类型的变量 pi 的地址:
    ppi = &pi;

    // 恭喜你,现在你已经知道了怎么定义 int** 类型的变量和给它赋值
    // 我们先写到这里
    return 0;
}

深入思考

假如定义有 int** p(为了方便,我们暂且把 p 认为是 ppi 的别名),那么 p, *p, **p, p + 1, *p + 1, *(p + 1), **p + 1, *(*p + 1), **(p + 1) 分别是什么?

先看指针自身

乍一看有点多,开始有点慌是吧,没关系,我们先看不带加法运算的前三个:p, *p 以及 **p
从上面的代码我们已经知道 p 就是存放 int* 类型变量的地址的变量

    // 从上面暂停下来的地方我们继续

    // 我们都知道,在指针前面加个 * 就是“取得这个指针指向的地址里的值”
    // 因为 pi 存放的是 i 的地址,那么 *pi 就是取得 i 存放的值,类型是 int
    // 同理,*ppi 取得的是 pi 存放的值,类型是 int*
    printf("*pi = %d, *ppi = %p\n", *pi, *ppi);
    // 输出 *pi = 418, *ppi = 0000002D6FF2FD58 (*pi = 后面的值在每台机器上都可能不一样)

    // 既然 *ppi 是 int*,那也就是说我们还可以对它再做一次解引用,
    // 拿到 *ppi 这个地址里存放的值,类型是 int
    printf("**ppi = %d\n", **ppi);
    // 输出 **pi = 418

这时,你已经掌握 p*p 以及 **p 分别是什么了

再看指针的加法运算

接下来我们还是先挑最简单的,把不带 * 的拿出来:p + 1,指针 p 做了个加法运算。

那么它加的这个 1 是什么?数字11位?1字节?

都不是,C指针加法运算里的数字操作数的单位是指针的长度,也就是说 p + 1 表示的时候内存中,紧挨着 p 的下一个可用空间的地址:

    printf("ppi = %p, ppi + 1 = %p\n", ppi, ppi + 1);
    // 输出 ppi = 0000008CA96FFB78, ppi + 1 = 0000008CA96FFB80
    // 并且我们可以看到 0000008CA96FFB80 - 0000008CA96FFB78 = 8(16进制)
    // 恰好等于 x64 系统下 1 个指针的大小:8 字节

*(p + 1) 是什么你应该也知道了,就是 p + 1 这个地址(假设是合法的)存放的值,类型是 int*
*p + 1 就是 *p 这个地址再偏移了 1 个指针长度

    printf("*ppi = %p, *ppi + 1 = %p\n", *ppi, *ppi + 1);
    // 输出 *ppi = 0000002D6FF2FD58, *ppi + 1 = 0000002D6FF2FD60
    
    printf("pi = %p\n", pi);
    // 输出 pi = 0000002D6FF2FD58
    // 可以看到 *ppi == p

好了,还剩下最后三个:**p + 1, *(*p + 1), **(p + 1),先试试结合上面的知识,想一下在我们的例子中这三个分别是什么,想好之后再看下面的答案检验一下自己理解得对不对:

  • **p + 1**p 取得的是 int,值是 418,所以 **p + 1 是 419
  • *(*p + 1)*p + 10000002D6FF2FD60,那么 *(*p + 1) 就是取得这个地址中的值(假设地址都是合法的)
  • **(p + 1):先对 p + 1 这个地址做解引用,得到新的地址 *(p + 1),然后再对新的地址做解引用,得到的是个 int(假设地址都是合法的)

再给你 int*** 你也能回答了

现在再给你 int***,相信你也知道它是什么并且知道它相关的运算是什么了:

C语法释义
int***指向指向指向整型的指针的指针的指针
...指向 ... 的指针

拓展阅读

细心的你应该发现了,前面多次对指针做加法运算的时候都有注明假设地址合法,那么这个假设合法的地址到底是什么呢,可以阅读这篇《C指针与数组》(撰写中,敬请期待)

书籍推荐

标签: c

仅有一条评论

  1. Achille Achille

    不错不错!

添加新评论