The C ProgrammingLanguage 5.12复杂声明
以前没有深入使用过指针,感觉指针也不是很难。看过这章之后,感觉脑子不够用了,也看了很多文章,然后想自己写下来,忘记的话,可以再复习下。
首先书上给了几个例子。
- char **argv
- int(*daytab)[13]
- int *daytab[13]
- void *comp()
- void (*comp)()
- char (*(*x())[])()
- char (*(*x[3])())[5]
首先:一定得知道() / [] 的优先级都大于*,看声明从标识符看。
-
char (*(*x())[])()
step1: x()
x是一个函数
step2: *x()
函数返回一个指针
step3: (*x())[]
这个指针指向一个一维数组
step4: *(*x())[]
这个一维数组的元素是指针
step5: char *(*x())
这些指针指向一个函数,这个函数的返回值为char类型
结合起来就是:x是一个函数,这个函数返回一个指针,这个指针指向一个一维数组,这个数组里的元素也是指针,这些指针分别指向多个函数,这些函数的返回值为char类型。 -
char (*(*x[3])())[5]
step1: x[3]
x是一个具有3元素的一维数组
step2: *x[3]
这些元素都是指针
step3: (*x[3])()
这些指针指向函数
step4: *(x[3])()
这些函数返回一个指针
step5: char ((*x[3])())[5]
这个指针指向一个具有5个元素的一维数组,数组类型为char型。
结合起来就是:x是一个具有3个元素的一维数组,数组的元素是指针,这些指针指向函数,这个函数返回一个指针,这个指针指向一个具有5元素的数组,类型为char型。
下面的部分是书上的程序。
首先要清楚dcl和direct-dcl,声明和直接声明。
dcl,是带有*的声明,意思就是间接引用,需要通过这个指针指向其他的东西,去引申到其他东西.。
direct-dcl,直接解释的东西。
这个程序有很多全局变量,我们要先看下这些全局变量是什么。
变量 | 注释 |
---|---|
right-aligned | right-aligned |
int tokentype | 记录最后一个记号的类型 |
char token[] | 记录最后一个记号 |
char name[] | 记录变量名 |
char datatype[] | 记录数据类型 |
char out[] | 输出的内容 |
先看gettoken()函数,gettoken把读入的字符串分为4种情况
- 读入的是(,然后继续读取如果下一个是),则返回,并把tokentype置为PARENS并返回,如果不是则返回(。
- 读入的是【,则循环读取[后的内容,直到遇到】停止,并把内容保存到token数组,然后把tokentype置为BRACKETS并返回。
- 读入的是字母,则循环读取,直到字符不是数字或字母,并把内容保存到token数组,然后把tokentype置为NAME并返回。
- 最后一种情况直接返回。
然后是dcl()函数
dcl是用来分析声明的。
首先它调用gettoken继续读取字符串,碰到*,就让ns++,然后调用dirdcl
调用dirdcl用来分析*号之后的声明。
dirdcl函数
它用来分析*号之后的声明
它把字符串分为3种情况
- 读入的是(,如果是,则调用dcl,因为读入的是(的话,后面可能还有声明,所以要和dcl互相递归调用,如果dcl后面返回回来后,tokentype没有被置为)的话,说明语法错误,因为调用dcl的时候tokentype是(而必须有个)与之对应。
- 读入的是NAME,是个变量名说明要读完了,把token数组里的内容拷贝到name数组中
- 剩下的读入都是错误的语法,因为你*号后不可能接着除了变量名和(号以外的字符了。
- 读到变量名之后,就可以往out数组里写东西进行翻译了,因为后面不是()号就是[]号了