在定义指针的时候,写成「int* p;」和「int *p;」哪个更好?

在学习到C++的“引用”之前,我是支持在纯C中使用

int *p;

这种写法的。相比直接将int*理解为指针(虽然更human friendly一些),上面的“运算式”写法避免了对*符号理解的二义性,即可以永远将*理解为“按址取值”的一个运算符,“p类型为指针”的结论由编译器根据“*pint类型”这个声明反推出来。更重要的是这个理解方式可以应用到更加复杂的类型声明语句中,比如典型的

char *argv[];

要声明的变量名argv按照既定的运算顺序(一元运算符优先级最高,且遵循从右向左的结合顺序),先执行数组索引运算,再执行按址取值运算,最终得到char类型,那么就可以反推出

argv[i]为指向char的指针,从而argv为一个由char指针组成的数组。当然这个例子即使用char* argv[]理解也是OK的,还不能体现前者的优势,那么像下面这样带括号的呢?

int (*p)[N];

p在这里先执行按址取值运算,再执行数组索引运算,最终得到int类型,从而反推出

*p为一个长度为N的int数组,从而p为指向这个数组的一个指针

这样子理解虽然对编译器比较友好而反人类,但确实是精准无歧义的。

再比如二维数组,

int a[M][N];
int (*p)[N] = a;

凭什么下面的p能够无需类型转换地指向上面的a?仔细研究下就能体会到这种贴近编译器的理解方式的强大之处。甚至包括函数指针都可以按上述方式理解。

========分割线========

顺嘴可以说下强制类型转换,把声明表达式中的变量名和分号去掉,两侧套上括号不就结了?反正变量名的位置可以根据运算符的前后缀特性推出来,并不影响编译器的类型推导。比如

p2 = (int (*)[N])some_pointer;

虽然int (*)[N]这个类型转换符看起来挺复杂,但是只需考虑到*是前缀运算符,[]是后缀运算符,隐藏的变量名位置就显而易见了(没错正是int (*p)[N],这个填充是唯一的)。

========又一分割线========

int *p = &a;

该作何解释的问题。这个问题其实只要换成一个像上面一样复杂的声明就好理解了

int a[M][N];
some_type line = a[0];    /* a的第一行,一个长度N的数组 */
int (*p)[N] = &line;    /* p作为一个指向数组的指针的声明初始化 */

你会觉得这个初始化语句等价于

int (*p)[N];
p = &line;

还是

int (*p)[N];
(*p)[i] = &line;

呢?

即使不好分析p是什么,(*p)[i]是一个int是显然的结论,由此可看出无论p的声明表达式有多复杂,初始化语句的等号左边永远都会是一个由保留关键字int/char/long/float/double定义的基本数据类型,如果后者成立,一切派生类型的初始化就都完犊子了。所以合理的理解方式只能是前者。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值