C语言函数嵌套的用法(附带实例)
C语言虽然不允许进行函数嵌套定义,但却可以函数嵌套调用,即可在一个函数体内可以调用另外一个函数。
例如,在 main() 函数中调用 Display() 函数,在 Display() 函数中再调用 ShowMessage() 函数,这种就叫作嵌套调用。
调用时,一般从最外层 main() 函数开始,一层层的调用,直到深入最内层的函数。嵌套调用返回时,恰好相反,从最内层的函数开始,一层层返回,直到返回最外层的主调函数中。
这就好比某公司要完成业绩,CEO 需要将运营指标交代给总经理,总经理将工作分拆给各部门经理(副经理),部门经理们再将工作分拆给下属职员,职员按照上级指示完成具体工作。之后,职员将完成结果汇报给部门经理,部门经理汇总后将结果汇报给总经理,总经理再汇总后将结果汇报给 CEO。
【实例】利用嵌套函数模拟 CEO 分派工作的过程。这里简化任务的完成过程,只输出一条语句表示逐级分派任务(即调用函数)的过程。
运行程序,输出结果为:
函数可以直接调用自己,也可以间接调用自己,如下图所示。所谓间接调用,就是在递归函数的下层函数中调用自己。

图 1 递归调用过程
递归之所以能实现,是因为函数的每个执行过程在栈中都有自己的形参和局部变量副本,这些副本和该函数的其他执行过程不发生关系。这种机制是当代大多数程序设计语言实现子程序结构的基础。
【实例】倒序输出名单。定义一个字符串数组,为其赋值一系列名称,通过递归函数调用,逆序显示名单。注意,本例之所以能逆序输出名单,是因为嵌套函数返回时是从最内层到最外层逐层返回。

图 2 程序调用流程图
运行程序,输出结果为:
例如,在 main() 函数中调用 Display() 函数,在 Display() 函数中再调用 ShowMessage() 函数,这种就叫作嵌套调用。
调用时,一般从最外层 main() 函数开始,一层层的调用,直到深入最内层的函数。嵌套调用返回时,恰好相反,从最内层的函数开始,一层层返回,直到返回最外层的主调函数中。
这就好比某公司要完成业绩,CEO 需要将运营指标交代给总经理,总经理将工作分拆给各部门经理(副经理),部门经理们再将工作分拆给下属职员,职员按照上级指示完成具体工作。之后,职员将完成结果汇报给部门经理,部门经理汇总后将结果汇报给总经理,总经理再汇总后将结果汇报给 CEO。
【实例】利用嵌套函数模拟 CEO 分派工作的过程。这里简化任务的完成过程,只输出一条语句表示逐级分派任务(即调用函数)的过程。
#include<stdio.h> void CEO(); /* 声明 4 个函数 */ void Manager(); void AssistantManager(); void Clerk(); int main() { CEO(); /* 调用 CEO 函数 */ return 0; } void CEO() /* 定义 CEO 函数 */ { printf("CEO 交代给总经理\n"); Manager(); /* 调用 Manager 函数 */ } void Manager() /* 定义 Manager 函数 */ { printf("总经理交代给部门经理\n"); AssistantManager(); /* 调用 AssistantManager 函数 */ } void AssistantManager() /* 定义 AssistantManager 函数 */ { printf("部门经理交代给各个职员\n"); Clerk(); /* 调用 Clerk 函数 */ } void Clerk() /* 定义 Clerk 函数 */ { printf("职员开始执行\n"); }
- 首先在程序中声明将要使用的 4 个函数,其中的 CEO 代表公司总裁,Manager 代表总经理,AssistantManager 代表副经理,Clerk 代表职员。
- main() 函数下是 4 个函数的定义。先来看一下 CEO() 函数,通过输出一条信息来表示这个函数的功能和作用,然后嵌套调用 Manager() 函数。Manager() 和 CEO() 函数运行的步骤是相似的,最后在其函数体内调用 AssistantManager() 函数。在 AssistantManager() 函数中调用 Clerk() 函数。
- 在主函数 main() 中,调用了 CEO() 函数,于是程序的整个流程按照步骤(2)进行,直到“return 0”语句返回,程序结束。
运行程序,输出结果为:
CEO 交代给总经理 总经理交代给部门经理 部门经理交代给各个职员 职员开始执行
C语言函数的递归调用
所谓递归调用,就是函数自己调用自己。从定义中可以看出,函数递归调用是函数嵌套调用的一种特殊形式。函数可以直接调用自己,也可以间接调用自己,如下图所示。所谓间接调用,就是在递归函数的下层函数中调用自己。

图 1 递归调用过程
递归之所以能实现,是因为函数的每个执行过程在栈中都有自己的形参和局部变量副本,这些副本和该函数的其他执行过程不发生关系。这种机制是当代大多数程序设计语言实现子程序结构的基础。
【实例】倒序输出名单。定义一个字符串数组,为其赋值一系列名称,通过递归函数调用,逆序显示名单。注意,本例之所以能逆序输出名单,是因为嵌套函数返回时是从最内层到最外层逐层返回。
#include<stdio.h> void DisplayNames(char** cNameArray); /* 声明递归函数 DisplayNames */ char* cNames[] = /* 定义字符串数组 */ { "Aaron", "Jim", "Charles", "Sam", "Ken", "end" /* 设置一个结束标志 */ }; int main() { DisplayNames(cNames); /* 调用 DisplayNames 函数 */ return 0; } void DisplayNames(char** cNameArray) /* 定义 DisplayNames 函数 */ { if(*cNameArray == "end") /* 判断是否是结束标志 */ { return ; /* 如果是,函数结束返回 */ } else { DisplayNames(cNameArray + 1); /* 如果不是,递归调用自身 */ printf("%s\n", *cNameArray); /* 输出字符串 */ } }如下图所示为程序的调用流程,通过此图读者可对递归调用过程有一个更直观的认识。

图 2 程序调用流程图
- 首先声明递归函数 DisplayNames(),其参数声明为指针的指针。
- 定义一个全局字符串数组,并且为其进行赋值。其中,字符串“end”作为数组的结尾标志。
- 在主函数 main() 中调用递归函数 DisplayNames()。
- 在 DisplayNames 的函数体中,通过 if 语句判断当前要输出的字符串是否是结束字符“end”,如果是,则使用 return 语句返回。否则,执行下面的 else 语句,调用递归函数,在函数参数处可以看到传递的字符串数组元素发生改变,传递下一个数组元素。调用递归函数后,仍然要先判断传递进来的字符串是否是数组的结束标志。最后输出字符串数组的元素。
运行程序,输出结果为:
Ken Sam Charles Jim Aaron