在C程序设计语言5-18题中,在dcl程序中,我们看到dcl()和dirdcl()函数相互调用,形成递归。原书成为recursive-descent,有相关资料翻译成递归下降。其实翻译成交叉递归更为合理。但这种实现方法比较难于理解的,gdb中函数跳来跳去,想了解程序实际流程很困难。这时,有个小技巧可以帮助我们理解代码时序。
void dcl(void) {
static int dclcount = 0;
printf(“this is the %d 次调用dcl start\n”,++dclcount);
printf(“token is %s\n”,token);
printf(“out is %s\n”,out);
int ns;
for (ns = 0;gettoken() == ‘*’?
ns++;
dirdcl();
while (ns–)
strcat(out," pointer to");
printf(“this is the %d 次调用dcl terminate\n”,dclcount–);
printf(“token is %s\n”,token);
printf(“out is %s\n”,out);
}
void dirdcl(void) {
static int dirdclcount = 0;
printf(“this is the %d 次调用dirdcl start\n”,++dirdclcount);
printf(“token is %s\n”,token);
printf(“out is %s\n”,out);
int type;
if (tokentype == ‘(’) {
dcl();
if (tokentype != ‘)’)
printf(“error:missing )\n”);
} else if (tokentype == NAME )
strcpy(name,token); /数据类型前面已经取到了,这里取的是数据名称/
else
printf(“error:expected name or (dcl)\n”);
while ((type = gettoken()) == PARENS || type== BRACKETS)
if (type == PARENS)
strcat(out," function returning “);
else {
strcat(out, " array”);
strcat(out, token);
strcat(out," of");
}
printf(“this is the %d 次调用dirdcl terminate\n”,dirdclcount–);
printf(“token is %s\n”,token);
printf(“out is %s\n”,out);
}
这里有3个关键点:
1.在函数内声明static型的计数变量,这样,在反复递归调用该函数时,该变量不会被重新初始化。这样我们就可以清楚了解该函数的调用顺序。
2.在函数开始和结尾分别打印该变量。注意两个++,–的位置。只有这样,才能确保这对打印的是同一个函数的计数。
开始:printf(“this is the %d 次调用dirdcl start\n”,++dirdclcount);
结尾:printf(“this is the %d 次调用dirdcl terminate\n”,dirdclcount–);
3.在打印计数变量后可以跟着打印你想了解的变量信息。结果如下:
int (*ptr)()
this is the 1 次调用dcl start
token is int
out is
this is the 1 次调用dirdcl start
token is int
out is
this is the 2 次调用dcl start
token is int
out is
this is the 2 次调用dirdcl start
token is ptr
out is
this is the 2 次调用dirdcl terminate
token is ptr
out is
this is the 2 次调用dcl terminate
token is ptr
out is pointer to
this is the 1 次调用dirdcl terminate
token is ()
out is pointer to function returning
this is the 1 次调用dcl terminate
token is ()
out is pointer to function returning
ptr: pointer to function returning int