如何理解C/C++中的多级指针与数组中的top-level-const与low-level-const

前言

关于多级指针中的 const 修饰初学者都会觉得是一个很玄学的问题,我也是初学者,在深入理解后在此留下一些自己的理解,使用更多的示例与图示用这篇短文来展示理解的过程。同时也发现在这一块文章也不多,因此希望此文能对你有帮助。

  • top-level-const :顶级常量,指指针本身是常量。
  • low-level-const :低级常量,指指针指向的量是常量。

玄学 const 指针

int *p;				// 指向变量的指针变量
const int *p;		// 指向常量的指针变量
int const *p;       // 等价于 const int *p
int * const p;		// 指向变量的指针常量
const int * const p; // 指向常量的指针变量

玄学数组指针

int *p[4];			// 指向 int 的指针数组, sizeof(*p) == sizeof(int)
int (*p)[4];		// 指向数组的指针, sizeof(*p) == sizeof(int) * 4

如何理解 const 指针

我们以 const int * const p 来从编译器的角度解释这个变量声明是如何被解析的。

编译器是从右往左解析这串声明的。事实上很多的表达式对于编译器而言都是从右往左解析的,尽管大多数是从左往右,这里不展开。

  • 首先,编译器知道我们声明了一个变量 p ,但因为编译器从右往左解析,它目前不知道 p 是任意数据类型。
  • 编译器解析到了第二个 const ,因此 p 是一个 const 修饰类型。
  • 解析到 * ,因此 const p 是一个指针类型,但是目前我们只能说它是一个指针,但不知道它指向何种数据类型。可以认为是 void * const p
  • 注意这时解析到 int 时已经开始确定 void * const p 指向的内容了,即确定 void 的类型,这里确定了 void * const p 指向一个 int 类型。
  • 最后解析到第一个 const ,因此最后得到 void * const p 指向 const int 类型。
void * const p
const int

看到这里,那么你应该也可以自己解释上面的一些其他例子了吧,后面还会举一些更复杂的例子。

const int * const ** const p

const int | * const | * | * const p| 仅用于理解)

void * const p
void *
void * const
const int

const int **** p

const int | * | * | * | * p| 仅用于理解)

void * p
void *
void *
void *
const int

可见可以把 * 当作解释的分隔符从右往左解释变量的申明。

如何理解数组指针

首先我们需要知道, [] 的优先级高于 * ,并且 [] 是自左向右结合的

我们现在从 int (*p)[4] 入手解释如何理解数组指针,通过之前对于玄学指针的解释应该可以自行从编译器角度理解这段申明,下面我想从方法论的角度分析如何理解。

考虑到 [] 是向左结合的,并且具有比 * 高的优先级,我们可以把 [] 翻译成向右结合的形式方便更直观的理解,上面的示例 int (*p)[4] 可以转化为 int[4]*p(将 [] 放到紧贴着前面的括号的前面) 。这样可以很直观的看到:p 首先是一个指针,指向一个包含 4 个元素的数组,数组包含的元素是 int

void * p
[4]
int

后面再来举一些更复杂的例子吧。

const int p[4]

const int | [4] p

p[4]
const int

const int * const (* const p[4])[5][6]

const int | * const | [6] | [5] | * const | [4] p

p[4]
void * const
[5]
[6]
void * const
const int

const char *(*p)[10][3]

const char * | [3] | [10] | * p

void * p
[10]
[3]
const char *

多级指针的应用

最后还是想简单介绍一下多级指针的应用,在 C 中没有封装的概念,因此许多用法必须要多级指针的支持;在 C++ 中,即使支持多级的封装,但是许多提供的接口同时支持 C/C++,因此依然是 C 的。

例如,我想要存储一张 10 × 3 10\times3 10×3 的表格,表格存储字符串,并且现在要求表格是静态的、字符串长度是动态的。那么就需要类似上一个示例 char *p[10][3] ;此时我又要求传入的指针在接口内可以任意修改,那么就必须申明为 char *(*p)[10][3] ;如果要求表格的行数得是动态的而列数是静态的,那么就必须申明为 char *(**p)[3] ;现在要求全部是动态的,char ****p,最后这种形式其实是十分常用的形式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值