首页 > 编程笔记 > C语言笔记 阅读:27

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

在生活中,为了能完成某项特殊的工作,可能需要使用具有特定功能的工具。在使用工具之前需要先制作这个工具,工具制作完成后,才可以使用。

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();    /*正确,在函数体内进行函数的嵌套调用*/
}
嵌套过程如下:
可用一个例子来理解嵌套过程,某公司的 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岁

相关文章