C语言中的 int** 是什么?
从 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 = π
// 恭喜你,现在你已经知道了怎么定义 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
是什么?数字1
?1
位?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 + 1
是0000002D6FF2FD60
,那么*(*p + 1)
就是取得这个地址中的值(假设地址都是合法的)**(p + 1)
:先对p + 1
这个地址做解引用,得到新的地址*(p + 1)
,然后再对新的地址做解引用,得到的是个int
(假设地址都是合法的)
再给你 int***
你也能回答了
现在再给你 int***
,相信你也知道它是什么并且知道它相关的运算是什么了:
C语法 | 释义 |
---|---|
int*** | 指向指向指向整型的指针的指针 的指针 |
... | 指向 ... 的指针 |
拓展阅读
细心的你应该发现了,前面多次对指针做加法运算的时候都有注明假设地址合法
,那么这个假设合法的地址
到底是什么呢,可以阅读这篇《C指针与数组》(撰写中,敬请期待)
不错不错!