第 7 章 用函数实现模块化程序设计
7.1 为什么要用函数
函数就是功能,每一个函数用来实现一个特定的功能。
在设计一个较大的程序时,往往采用模块化程序设计的思路,把它分成若干个程序模块,每一个模块包括一个或多个函数每个函数实现一个特定的功能。一个 C 程序可由一个主函数和若干其它函数构成。
说明:
- 一个 C 程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。
- 一个源程序文件由一个或多个函数以及其他有关内容(如指令、数据声明与定义等)组成。一个源程序文件是一个编译单位。
- C 程序的执行是从 main 函数开始的,也是在 main 函数中结束整个程序的运行。
- 函数定义是独立的。函数间可以互相调用,但不能调用 main 函数。
- 从用户使用的角度看,函数包括库函数和用户自定义函数两种。
- 从函数的形式看,函数分为无参函数和有参函数两类。
7.2 怎样定义函数
7.2.1 为什么要定义函数
C 语言要求函数必须先定义后使用。
函数定义要包括函数名、函数类型、函数参数名和参数类型以及函数功能(函数体)。
7.2.2 定义函数的方法
1. 定义无参函数
定义无参函数的一般形式为:
类型名 函数名(void)
{
函数体
}
括号内的 void 表示函数没有参数,void 可省略。
2. 定义有参函数
定义有参函数的一般形式为:
类型名 函数名(形式参数列表)
{
函数体
}
若函数体为空,则称为空函数。
7.3 调用函数
7.3.1 函数调用的形式
函数调用的一般形式为:
函数名(实参列表)
若调用无参函数,则实参列表可以没有。
7.3.2 函数调用时的数据传递
1. 形式参数和实际参数
在调用有参函数时,主调函数和被调函数之间有数据传递关系。定义函数时的参数称为形式参数(形参),调用函数时的参数称为实际参数(实参)。
2. 实参和形参间的数据传递
在调用函数过程中,系统会把实参的值传递给被调用函数的形参。形参的值仅在调用期间有效。
说明:
- 实参可以时常量、变量或表达式。
- 实参和形参的类型应该保证赋值兼容。
7.3.3 函数调用的过程
- 定义函数中指定的形参在未发生函数调用时并不占用内存中的存储单元。在发生函数调用时,函数的形参才被临时分配内存单元。
- 在发生函数调用时,将实参的值传递给对应形参。
- 在函数调用期间,形参的值参与有关运算。
- 通过 return 语句将函数值返回给主调函数。函数返回值的类型要与函数类型一致。如果没有返回值,则函数的类型应定义为 void。
- 函数调用结束后,形参单元被释放。实参单元保留不变。实参和形参是两个不同的存储单元。
注意:实参向形参的数据传递时值传递,只能由实参传给形参。实参和形参在内存中占用不同的存储单元。
7.3.4 函数的返回值
通过函数调用可以得到一个函数值(函数返回值)。
说明:
- 函数的返回值是通过函数中的 return 语句获得的。
- 如果函数有返回值,定义函数时要指定函数值的类型。
- 函数类型决定函数返回值的类型,可以自动进行类型转换。
- 对于不带返回值的函数,定义函数为“void 类型”。
7.4 对被调用函数的声明和函数原型
- 被调用的函数必须是已经定义的函数。
- 调用库函数要用
#include
指令引用有关头文件。 - 调用用户自定义函数要在主调函数中对被调用的函数作声明。
函数首部称为函数原型,使用函数首部进行函数声明。函数首部包含了函数名、函数类型、参数个数和参数顺序,从而可以对函数调用的合法性进行检查。
函数声明的一般形式有两种:
函数类型 函数名(参数类型 1 参数名 1, ..., 参数类型 n 参数名 n);
函数类型 函数名(参数类型 1, ..., 参数类型 n);
函数声明中可以省略形参名。
注意:函数的定义是指对函数功能的确立,包括函数名、函数值类型、形参及其类型以及函数体。函数声明的作用是将函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用时进行检查,它不包括函数体。
7.5 函数的嵌套调用
C 语言的函数不能嵌套定义,但可以嵌套调用,即在调用一个函数的过程中,又调用另一个函数。
7.6 函数的递归调用
在调用一个函数的过程中直接或间接的调用函数本身,称为函数的递归调用。
程序中不应出现无终止的递归调用,而应是有限次数的、有终止的递归调用。