< 返回博客

C语言的声明规律


C语言中的基础语法其实很简单,但是有时候各种符号套来套去就让人很头疼,像天书一样。但是一门语言设计出来肯定是有简单的规律可以总结的,如果掌握了这些,很多东西就变得容易起来了。
首先来看看下面两句代码:

int *p1[10];
int (*p2)[10];

熟悉C语言的朋友可能一眼看出:p1是一个指针数组,存储的是10个整型指针;p2是一个指向数组的指针,一般称作数组指针,它仅仅是一个指针,指向一个二维数组。
这个该怎么理解呢?在网上搜索“数组指针 指针数组”答案有好多,一般都是从优先级的角度来分析,这里我给出另一种理解方式。
想一下,我们平时在使用C语言的变量时,声明方式和使用方式是不是特别相似:int a,使用起来a就是一个int型的值;同样的,int str[5][10]声明了一个“五行十列”的整型数组,而恰好,str[a][b]就是第a行第b列的int型的值。一般来说,对于一个变量声明,比如type *a,我们把基本类型type去掉,然后以剩下部分的方式来使用这个变量,得到的类型就是这个type类型。
了解了这个,我们看看开头的例子。int *p1[10]去掉int,得到*p1[10],想一下这个表达式的意义:由于[]的优先级高于*,所以首先解析p1[10],从这里就可以看出一点端倪——p1是个数组,是个什么数组呢?*p1[10]就表明了这个数组元素是可以解除引用的,所以是个指针数组。什么类型的?表达式已经结束,结合我们去掉的int,可以得出,这是个数组,数组的每个元素都是一个指针,而且是个int型指针。
是不是挺容易的。再看看下面这个:int (*p2)[10]。想象你已经拥有了p2,接下来想要用它。首先去掉int,得到(*p2)[10],然后使用这个表达式:*p2说明p2可以解除引用,是个指针;对(*p2)使用[10],可以得出(p2)的结果是个长度为10的数组,最后,结合去掉的int,得出这是一个数组的指针。
同样的“巧合”存在于C语言的很多地方,比如typedef
假设现在有一个已声明的结构体struct test,使用typedef struct test Test很好理解:Teststruct test的一个别名;那么使用typedef struct test Testptr怎样理解?和上面一样,去掉前缀typedef,然后把剩下的struct test *Testptr当成一个表达式,这时候变量Testptr是一个struct test的指针,所以,整体typedef struct test *Testptr中的Testptr就是一个struct test的指针。
这种语法其实不算巧合,毕竟独立于使用方式而重新规定一套声明方式,不论是对程序员还是编译器的设计,都是负担,这种方式其实是可以大大减少理解难度的。