分类: C/C++
2009-07-29 11:36:19
理解复杂类型的关键
构成复杂声明的基本元素是类型说明符和数据类型名。理解复杂类型的关键是理解并正确运用类型说明符和数据类型名在解释过程中的优先级和结合性。
复杂声明中的类型说明符有:()、[]、*三种。其中()用于说明函数类型以及改变说明的先后顺序;[]用于说明数组类型;*则用于说明指针类型。数据类型名可以是int、char、float、double、void等基本类型名,也可以是用户自定义的构造类型。
在解释复杂声明时,要按照()、[]优先级最高,*次之,而数据类型名的优先级最低的顺序来解释。当()和[]同时在复杂声明中出现时,就需要考虑类型说明符的结合性。C语言规定,类型说明符()和[]的结合性是左结合,即按从左至右的顺序进行解释。
在具体的解释过程中,对复杂声明要按照优先级和结合性进行解释顺序的分解,确定解释的先后顺序,然后进行逐步分析,在每一步分析过程中要运用基本类型指针涉及的知识进行解释,最后归纳综合出复杂声明的含义。
以复杂声明char *(*(*f(char *(*para)(char *)))[2])();为例。首先按照类型说明符和数据类型名的优先级和结合性对其进行分解得到:
f ® (char * (*)(char * para)) ® * ® [2] ® * ® () ® * ® char
① ② ③ ④ ⑤ ⑥ ⑦
① f与(char * (*para)(char *))作用后可以得出:f是一个函数。char * (*para)(char *)是f函数的形参说明。它的解释顺序是:para ® * ® (char *) ® * ® char。即f函数的形参para是一个函数指针,所指向的函数有一个字符指针的形参,并且返回值是字符指针值。
② 与*作用后得出:f是一个指针函数。即f函数的返回值是一个指针值。
③ 与[3]作用后得出:f是一个指针函数,其返回值是指向有两个元素数组的指针。
④ 与*作用后得出:f是一个指针函数,其返回值是指向有两个元素的指针数组的指针。
⑤ 与()作用后得出:f是一个指针函数,其返回值是指向有两个元素的函数指针数组的指针,函数指针数组中的指针元素所指函数无参。
⑥ 与*作用后得出:f是一个指针函数,其返回值是指向有两个元素的函数指针数组的指针,函数指针数组中的指针元素所指函数无参,其返回值为指针值。
⑦ 与char作用后得出:f是一个指针函数,其返回值是指向有两个元素的函数指针数组的指针,函数指针数组中的指针元素所指函数无参,其返回值为字符指针值。
所以,上面的复杂说明说明f是一个指针函数;其形参para是一个函数指针,para所指向的函数有一个字符指针的形参,返回值是字符指针值;并且,f函数的返回值是指向有两个元素的函数指针数组的指针,函数指针数组中的指针元素所指函数无参,其返回值为字符指针值。其物理含义可以由图1表示。
|
|
… |
|
char * f00();
char * f01();
f(char *(*para)(char *));
char * f21(); …
图1复杂声明char *(*(*f(char *(*para)(char *)))[2])();物理含义的图示
4 复杂类型的应用
要掌握复杂声明,就需要在理解复杂声明的基础上进一步使用复杂声明。它可以进一步反过来强化对复杂声明的理解。仍以char *(*(*f(char *(*para)(char *)))[2])();为例,讨论如何使用f。首先要构造f函数的形参,其次要构造f函数的返回值。
f函数的形参是一个指向有字符指针形参的字符指针函数的函数指针。因此在 main函数中通过char *(*pf)(char *);声明了pf为函数指针;同时,通过声明char * fun(char *s);和pf=fun;使函数指针pf指向函数fun。这样,通过f(pf)就可以调用f函数。
由于f函数的返回值是指向有两个元素的函数指针数组的指针,因此需要声明一个二维函数指针数组a,在f函数中通过char *(*(*pa)[2])();声明pa是指向有两个元素的函数指针数组的指针,通过pa=a就使pa指向了二维函数指针数组a。
同时,在f函数中通过pa向二维函数指针数组a的各个元素进行赋值。从a[0][0]开始,到a[2][1]为止,各个元素依次指向函数f00到f21。通过return pa;将指向二维函数指针数组a的指针值返回。
与此同时,在main函数中通过p=f(pf);使p指向二维函数指针数组a。在双重循环中通过(*p[i][j])()依次调用函数f00、f01、…、f20、f21。也可以用p[i][j]()的形式来进行调用。
相应的程序如下:
#include "stdio.h"
char * fun(char *s); /* fun是有字符指针形参的字符指针函数 */
char *(*(*f(char *(*para)(char *)))[2])();
char *f00(); char *f01(); /* f00到f21都是无参字符指针函数 */
char *f10(); char *f11();
char *f20(); char *f21();
char *(*a[3][2])(); /* 声明二维函数指针数组a */
void main(void)
{
char * (*(*p)[2])(); /* p是指向有两个元素的函数指针数组的指针 */
char *(*pf)(char *); /* pf是指向有字符指针形参的字符指针函数的函数指针 */
int i,j;
pf=fun; /* 对pf赋值,使pf指向函数fun */
p=f(pf); /* 调用f函数,返回指向二维函数指针数组指针值赋给指针p */
for(i=0;i<3;i++)
for(j=0;j<2;j++)
printf("%s\n",(*p[i][j])()); /* 通过指针p调用f00、…、f21 */
}
char *f00() /* 定义函数f00 */
{
static char s00[]="function f00 is called!";
return s00;
}
char *f01() /* 定义函数f01 */
{
static char s01[]="function f01 is called!";
return s01;
}
char *f10() /* 定义函数f10 */
{
static char s10[]="function f10 is called!";
return s10;
}
char *f11() /* 定义函数f11 */
{
static char s11[]="function f11 is called!";
return s11;
}
char *f20() /* 定义函数f20 */
{
static char s20[]="function f20 is called!";
return s20;
}
char *f21() /* 定义函数f21 */
{
static char s21[]="function f21 is called!";
return s21;
}
char *(*(*f(char *(*para)(char *)))[2])() /* 定义函数f */
{
char *(*(*pa)[2])(); /* 声明指向有两个元素的函数指针数组的指针pa */
char *pret;
pa=a; /* 使pa指向二维函数指针数组a */
pret=(*para)("this is a test!");/* 调用para所指函数,返回值赋给pret */
printf("in function f, pret is %s\n",pret); /* 输出pret所指对象 */
pa[0][0]=f00;pa[0][1]=f01; /* 对二维函数指针数组的元素进行赋值 */
pa[1][0]=f10;pa[1][1]=f11;
pa[2][0]=f20;pa[2][1]=f21;
return pa; /* 返回指向二维函数指针数组的指针 */
}
char * fun(char *s) /* 定义有字符指针形参的字符指针函数fun */
{
printf("in function fun, s is %s\n",s);
return s;
}
程序的运行结果如下:
in function fun, s is this is a test!
in function f, pret is this is a test!
function f00 is called!
function f01 is called!
function f10 is called!
function f11 is called!
function f20 is called!
function f21 is called!