C语言函数调用的5种方法(附带实例)
在生活中,为了能完成某项特殊的工作,可能需要使用具有特定功能的工具。在使用工具之前需要先制作这个工具,工具制作完成后,才可以使用。
C语言中的函数就像要实现某项功能的工具,而使用函数的过程就是函数的调用。
函数的调用方式有 5 种,包括函数语句调用、函数表达式调用、函数参数调用、函数嵌套调用和函数递归调用。
定义一个函数,使用函数语句调用方式,通过调用函数实现输出一条信息的功能,进而观察函数语句调用的使用方式。
具体代码如下:
运行程序,结果为:
定义一个函数,其功能是利用欧姆定律(R=U/I)计算电阻值,并在表达式中调用该函数,使得函数的返回值参加运算得到新的结果。
具体代码如下:
编写 getTemperature() 函数返回体温,将返回的结果传递给 judgeTemperature() 函数。把函数作为参数使用,在程序中定义 getTemperature() 函数,又定义 judgeTemperature() 函数,而 judgeTemperature() 的参数是 getTemperature()。
具体代码如下:
例如,下面的代码是错误的:
虽然 C语言不允许进行嵌套定义,但是可以嵌套调用函数,也就是说,在一个函数体内可以调用另外一个函数。例如,使用下面的代码进行函数的嵌套调用:
可用一个例子来理解嵌套过程,某公司的 CEO 决定该公司要完成一个方向的目标,但是要完成这个目标就需要将其讲给公司的经理,公司中的经理需将要做的内容再传递给下级的副经理,副经理再讲给下属职员,职员按照上级的指示进行工作,最终完成目标。其过程如下图所示。

图 1 嵌套过程
利用嵌套函数模拟上述比喻中描述的过程,将每一个位置的人要做的事情封装成一个函数,通过调用函数完成最终目标。具体代码如下:
直接递归调用过程如下图所示:

图 2 直接递归调用过程
间接递归调用,是指在递归函数调用的下层函数中再调用原函数。间接递归调用过程如下图所示。

图 3 间接递归调用过程
从图 2 和图 3 可以看出,这两种递归调用都是无止境地调用自身。程序不应该出现这样无止境的循环,应该有结束条件。通常可在函数内部加一个条件判断语句,在满足条件时停止递归调用,然后逐层返回。
这种机制是目前大多数程序设计语言实现子程序结构的基础,这也使得递归成为可能。假定某个调用函数调用了一个被调用函数,再假定被调用函数又反过来调用了调用函数,那么第二个调用就称为调用函数的递归,它发生在调用函数的当前执行过程结束之前。
而且,因为原先的调用函数、现在的被调用函数在栈中较低的位置有独立的一组参数和自变量,原先的参数和变量将不受任何影响,所以递归能正常进行。
例如,有 5 个人坐在一起,猜第 5 个人的年龄。戊说比丁大 2 岁,问丁的岁数;丁说比丙大 2 岁,问丙的岁数;丙说比乙大 2 岁,问乙的岁数;乙说比甲大 2 岁,问甲的岁数;甲说他 10 岁。下图所示是岁数的示意图,一层调用一层。

图 4 递归调用示意图
用递归的方式求上述例子中戊的年龄。具体代码如下:
C语言中的函数就像要实现某项功能的工具,而使用函数的过程就是函数的调用。
C语言函数的调用方式
一种工具可能不止有一种使用方式,就像雨伞一样,它既可以遮雨也可以遮阳光,函数的调用也是如此。函数的调用方式有 5 种,包括函数语句调用、函数表达式调用、函数参数调用、函数嵌套调用和函数递归调用。
1) 函数语句调用
把函数调用作为一条语句就称为函数语句调用。函数语句调用是常使用的调用函数的方式。定义一个函数,使用函数语句调用方式,通过调用函数实现输出一条信息的功能,进而观察函数语句调用的使用方式。
具体代码如下:
#include <stdio.h> /* 包含头文件 */ void Display() /* 定义函数 */ { /* 输出一条信息的功能 */ printf("三人行,必有我师焉,择其善者而从之,其不善者而改之 \n"); } int main() /* 主函数 main() */ { Display(); /* 调用函数输出语句 */ return 0; /* 程序结束 */ }在介绍定义与声明函数时曾说明过,如果在使用函数之前定义函数,那么此时的函数定义包含函数声明。
运行程序,结果为:
三人行,必有我师焉,择其善者而从之,其不善者而改之
2) 函数表达式调用
函数出现在一个表达式中,这时会要求函数必须返回一个确定的值,这个值则作为参加表达式运算的一部分。定义一个函数,其功能是利用欧姆定律(R=U/I)计算电阻值,并在表达式中调用该函数,使得函数的返回值参加运算得到新的结果。
具体代码如下:
#include <stdio.h> /* 包含头文件 */ /* 声明函数,进行计算 */ void TwoNum(float iNum1, float iNum2); int main() { TwoNum(5, 10); /* 调用函数计算表达式的值 */ return 0; } void TwoNum(float iNum1, float iNum2) /* 定义函数 */ { float iTempResult; /* 定义整型变量 */ /* 进行计算,并将结果赋给 iTempResult */ iTempResult = iNum1 / iNum2; printf("电阻值是 %f\n", iTempResult); /* 输出电阻值 */ }运行程序,结果为:
电阻值是 0.500000
3) 函数参数调用
将函数作为另一个函数的实参调用,这样将函数返回值作为实参传递到函数中使用。函数出现在一个表达式中,这时要求函数返回一个确定的值,这个值会参加表达式的运算。编写 getTemperature() 函数返回体温,将返回的结果传递给 judgeTemperature() 函数。把函数作为参数使用,在程序中定义 getTemperature() 函数,又定义 judgeTemperature() 函数,而 judgeTemperature() 的参数是 getTemperature()。
具体代码如下:
#define _CRT_SECURE_NO_WARNINGS /* 解除 vs 安全性检测问题 */ #include <stdio.h> /* 包含头文件 */ void judgeTemperature(int temperature); /* 声明函数 */ int getTemperature(); /* 声明函数 */ int main() /* 主函数 main() */ { judgeTemperature(getTemperature()); /* 调用函数 */ return 0; /* 程序结束 */ } int getTemperature() /* 定义体温函数 */ { int temperature; printf("please input a temperature:\n"); /* 输出提示信息 */ scanf("%d", &temperature); /* 输入体温 */ printf("当前体温是: %d\n", temperature); /* 输出当前体温 */ return temperature; /* 返回体温 */ } void judgeTemperature(int temperature) /* 自定义体温正常函数 */ { if (temperature <= 312.3f && temperature >= 36) /* 判断体温是否正常 */ printf("体温正常 \n"); else printf("体温不正常 \n"); }运行程序,结果为:
please input a temperature:
35
当前体温是: 35
体温不正常
4) 函数嵌套调用
在 C语言中,函数的定义都是互相平行、独立的,也就是说在定义函数时,一个函数体内不能包含定义的另一个函数。例如,下面的代码是错误的:
int main() { void Display() /*错误!!!不能在函数内定义函数*/ { printf("I want to show the Nesting function"); } return 0; }从上面的代码可以看到,在主函数 main() 中定义了一个 Display() 函数,目的是输出一句提示信息。但 C语言是不允许进行嵌套定义的,因此编译时就会出现下面的错误提示:
[Error] a function-definition is not allowed here before '{' token
虽然 C语言不允许进行嵌套定义,但是可以嵌套调用函数,也就是说,在一个函数体内可以调用另外一个函数。例如,使用下面的代码进行函数的嵌套调用:
void ShowMessage() /*定义函数*/ { printf("The ShowMessage function"); } void Display() { ShowMessage(); /*正确,在函数体内进行函数的嵌套调用*/ }嵌套过程如下:
- 从主函数 main() 入口进入程序,执行 main() 函数开头部分;
- 执行到调用 Display() 函数时,程序转向执行 Display() 函数;
- 执行 Display() 函数,从 Display() 函数头开始执行,执行到调用 ShowMessage() 函数,程序转向执行 ShowMessage() 函数;
- 执行 ShowMessage() 函数,从函数头开始执行,如果没有其他嵌套函数,则完成 ShowMessage() 函数的全部操作;
- 转向执行 Display() 函数中尚未执行的部分,直到 Display() 函数执行结束;
- 返回 main() 函数中调用 Display() 函数的调用处;
- 继续执行 main() 函数剩余部分,直到 main() 函数执行结束。
可用一个例子来理解嵌套过程,某公司的 CEO 决定该公司要完成一个方向的目标,但是要完成这个目标就需要将其讲给公司的经理,公司中的经理需将要做的内容再传递给下级的副经理,副经理再讲给下属职员,职员按照上级的指示进行工作,最终完成目标。其过程如下图所示。

图 1 嵌套过程
在嵌套调用函数时,一定要在使用前进行原型声明。
利用嵌套函数模拟上述比喻中描述的过程,将每一个位置的人要做的事情封装成一个函数,通过调用函数完成最终目标。具体代码如下:
#include<stdio.h> void CEO(); /*声明函数*/ void Manager(); void AssistantManager(); void Clerk(); int main() { CEO(); /*调用CEO的作用函数*/ return 0; } void CEO() { /*输出信息,表示调用CEO()函数进行相应的操作*/ printf("CEO下达命令给经理\n"); Manager(); /*调用经理的作用函数*/ } void Manager() { /*输出信息,表示调用Manager()函数进行相应的操作*/ printf("经理下达命令给副经理\n"); AssistantManager(); /*调用副经理的作用函数*/ } void AssistantManager() { /*输出信息,表示调用AssistantManager()函数进行相应的操作*/ printf("副经理下达命令给职员\n"); Clerk(); /*调用职员的作用函数*/ } void Clerk() { /*输出信息,表示调用Clerk()函数进行相应的操作*/ printf("职员执行命令\n"); }运行程序,结果为:
CEO下达命令给经理
经理下达命令给副经理
副经理下达命令给职员
职员执行命令
5) 函数递归调用
在调用函数的过程中又直接或间接地调用其本身,称为函数的递归调用。递归调用分为直接递归调用和间接递归调用两种。直接递归调用过程如下图所示:

图 2 直接递归调用过程
间接递归调用,是指在递归函数调用的下层函数中再调用原函数。间接递归调用过程如下图所示。

图 3 间接递归调用过程
从图 2 和图 3 可以看出,这两种递归调用都是无止境地调用自身。程序不应该出现这样无止境的循环,应该有结束条件。通常可在函数内部加一个条件判断语句,在满足条件时停止递归调用,然后逐层返回。
这种机制是目前大多数程序设计语言实现子程序结构的基础,这也使得递归成为可能。假定某个调用函数调用了一个被调用函数,再假定被调用函数又反过来调用了调用函数,那么第二个调用就称为调用函数的递归,它发生在调用函数的当前执行过程结束之前。
而且,因为原先的调用函数、现在的被调用函数在栈中较低的位置有独立的一组参数和自变量,原先的参数和变量将不受任何影响,所以递归能正常进行。
例如,有 5 个人坐在一起,猜第 5 个人的年龄。戊说比丁大 2 岁,问丁的岁数;丁说比丙大 2 岁,问丙的岁数;丙说比乙大 2 岁,问乙的岁数;乙说比甲大 2 岁,问甲的岁数;甲说他 10 岁。下图所示是岁数的示意图,一层调用一层。

图 4 递归调用示意图
用递归的方式求上述例子中戊的年龄。具体代码如下:
#include<stdio.h> int getage(int n); //声明函数 int main() { int age; //定义整型变量,存储年龄 age = getage(5); //调用函数计算年龄 printf("戊的年龄是:%d岁\n", age); //输出戊的年龄 return 0; //程序结束 } int getage(int n) //自定义函数 { if (n==1) //如果是甲 { return 10; //返回10岁 } return 2 + getage(n - 1); //递归调用,调用getage()函数本身,同时加2 }运行程序,结果为:
戊的年龄是:18岁