C语言函数调用的5种方法(附带实例)

在生活中,为了能完成某项特殊的工作,可能需要使用具有特定功能的工具。在使用工具之前需要先制作这个工具,工具制作完成后,才可以使用。
C语言中的函数就像要实现某项功能的工具,而使用函数的过程就是函数的调用。
C语言函数的调用方式
一种工具可能不止有一种使用方式,就像雨伞一样,它既可以遮雨也可以遮阳光,函数的调用也是如此。
函数的调用方式有 5 种,包括函数语句调用、函数表达式调用、函数参数调用、函数嵌套调用和函数递归调用。
1) 函数语句调用
把函数调用作为一条语句就称为函数语句调用。函数语句调用是常使用的调用函数的方式。
定义一个函数,使用函数语句调用方式,通过调用函数实现输出一条信息的功能,进而观察函数语句调用的使用方式。
具体代码如下:
#include
void Display() /* 定义函数 */
{
/* 输出一条信息的功能 */
printf("三人行,必有我师焉,择其善者而从之,其不善者而改之 \n");
}
int main() /* 主函数 main() */
{
Display(); /* 调用函数输出语句 */
return 0; /* 程序结束 */
}
在介绍定义与声明函数时曾说明过,如果在使用函数之前定义函数,那么此时的函数定义包含函数声明。
运行程序,结果为:
三人行,必有我师焉,择其善者而从之,其不善者而改之
2) 函数表达式调用
函数出现在一个表达式中,这时会要求函数必须返回一个确定的值,这个值则作为参加表达式运算的一部分。
定义一个函数,其功能是利用欧姆定律(R=U/I)计算电阻值,并在表达式中调用该函数,使得函数的返回值参加运算得到新的结果。
具体代码如下:
#include
/* 声明函数,进行计算 */
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
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
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
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岁