一、为什么要用函数
人们在面对复杂应用时,常采用模块化设计方法,即把应用系统按功能划分为若干模块。
可以看出,每个模块具有特定的功能。在C程序中,这些模块都是用函数来表示的。
由于上层模块是利用下层模块搭建而成,故表示上下层模块的函数之间就存在所谓的调用关系,即上层模块的函数通过调用下层模块的函数来使用下层模块的功能。
二、怎样定义函数
在C语言中,函数的定义由函数头和函数体组成:
返回类型 函数名(参数列表) {
函数体
}
:
三、调用函数
准备阶段
执行阶段
返回阶段
#include <stdio.h>
int max(int x, int y)
{
int z;
if(x>y)z=x;
else z=y;
return z;
}
int main()
{
int c;
c= max(10, 20);
printf(”%d”,c);
return 0;
}
四、对被调用函数的声明和函数原型
函数A可通过调用函数B来使用函数B的功能。但在调用时经常会犯如下两类错误:
形参与实参个数不符
形参与实参类型不符
为了让编译器发现潜在的调用错误,要求及时对被调函数进行声明,具体做法如上。 当编译器在进行自上而下的编译时,能够及时获得被调函数的相关信息,进而发现调用错误,尽管此时尚未见到被调函数的具体定义。由于函数声明是借助于 函数原型(prototype)实现的,下面首先引入函数原型的概念。
五、函数的嵌套调用
函数的嵌套调用是指函数A调用函数B,函数B又调用函数C。
下面是一个嵌套调用的例子:
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
int main() {
int result = multiply(3, add(2, 4));
printf("结果是:%d\n",result);
return 0;
}
六、函数的递归调用
函数的递归调用是指一个函数直接或间接地调用它自己,这种函数称为递归函数。
下面是一个递归调用的例子,计算阶乘:
void f2(…) //定义f2
{ …
f3(…); //调用f3
…
}
float f3(…) //定义f3
{ …
f2(…); //调用f2
…
}
…
int f1(int x) //定义函数f1
{
…
y=f1(x+1); //调用自己
…
}
…
int main()
{
printf(“%d”, f1(100) );
…
}
递归函数是按照递归方法的思路编写的。递归方法的主要思想是把一个大规模问题的求解,不断转化为与它同类型的、但规模稍小问题的求解。
因此,递归方法/函数通常用于大事可化小的场合
七、数组作为函数参数
为方便起见,人们把函数的实参、形参统称为函数参数。下面来讨论数组作为函数参数的问题。
#include <stdio.h>
double max(double, double );
int main()
{
double a[10]={1.1,2.2,3.3},c;
c=max(a[0], a[2]);
printf("max is %f",c);
return 0;
}
double max(double x, double y)
{ double z;
z=(x>y)?x:y;
return z;
}
八、局部变量和全局变量
与政策法规类似,程序中定义的每个变量都有一个使用(有效)范围,变量可使用的范围称作变量的作用域。在作用域以外是不能访问该变量的。
按照变量的作用域,可把变量分为两大类:
局部变量( local variable ):在函数内或复合语句内定义的变量,其中包括函数的形参。
全局变量( global variable ):所有函数之外定义的变量(也称外部变量)。全局变量既可定义在程序开头,也可定义在中间位置。
九、变量的存储类别
对于全局变量,在程序开始执行时,系统为它在静态存储区里分配存储单元,而且在程序执行过程中,该变量始终占据此存储单元,直到程序结束才释放。
变量的这种存储方式被称为静态存储方式。
这样一来,在整个程序执行期间,全局变量的存储单元始终存在。人们把变量存储单元存在的时间段称为变量的生存期(寿命)。因此,全局变量的生存期为整个程序执行期间。
但是,对于函数的形参和局部变量,只有当调用开始时,系统才为它们在动态存储区里分配存储单元,而且一旦调用结束就立即释放。变量的这种存储方式被称为动态存储方式。
因此,局部变量的生存期为本函数被调用期间。