- 函数的声明
- 函数的定义
- 函数的调用
- 形式参数与实际参数
- 函数的调用过程
- 函数的声明与定义
- 函数的参数
- 数组元素作为函数的实参
- 数组名作为函数的参数
- 函数的变量
- 变量的声明和定义
- 局部变量和全局变量(作用域)
- 动态存储和静态存储(生存期)
- 数据的存储类别
- 内部函数与外部函数
- 例题汇总
- 例7.1初识函数
- 例7.2找最大值
- 例7.3返回值类型自动转换
- 例7.4求和
- 例7.5嵌套
- 例7.6递归1
- 例7.7递归2
函数是C语言中实现特定功能的程序块,也叫程序模块。 每一个函数实现一个特定的功能,当其他函数需要这个功能时,调用该函数即可。
模块化程序设计的思路就是,事先设计好各个功能的模块,需要的时候采用组装的办法来简化程序的设计。
函数的操作,具体有: 函数的声明、函数的定义、函数的调用 函数的声明
把函数的有关信息通知编译系统,以便编译系统对程序进行编译时,知道它们是函数。具体信息包括:函数名、函数类型、函数参数的个数和类型。
函数的定义“先定义,后使用”
定义函数包括以下内容:
- 函数的名字
- 函数的类型
- 函数参数的名字和类型
- 函数的具体操作,即实现什么功能
- 定义无参数的函数
类型名 函数名()
{
函数体
} - 定义有参数的函数
类型名 函数名(形式参数列表)
{
函数体
}
例:
int max(int x, int y) //函数类型为int整型,函数名为max,函数参数的名字为x、y,函数参数的类型为整型
//以下为函数的具体操作,此函数具体实现的功能为求两个数中的最大值
{
int z;
z = x>y ? x : y;
return z;
}
函数的调用
函数名(实参列表)
例:c = max(a, b);
对于有参数的函数,在函数定义阶段使用的参数为形式参数(例中的x和y),函数调用阶段使用的参数为实际参数(例中的a和b)
在函数的调用阶段,系统会将实参的值传递给被调用的函数的形参中,是**“值传递”**方式——数据传递的方向是从实参到形参,单向传递。形参与实参的数据类型应该相同,若有不同,实参的值会转换为形参的数据类型,再进行功能实现。
- 函数定义阶段到函数未被调用之前的这个阶段,函数中的形参不占内存中的存储单元。函数被调用时,形参才临时分配存储单元。
- 实参的值传递给形参。
- 执行函数功能,即运行函数体
- 通过return语句将函数运算的值返回调用函数。若函数不需要返回值,则函数的类型为void,且不需要return语句。
- 调用结束,形参单元被释放。实参的值从始到终是不会改变的,若形参的值发生改变,不会改变实参的值。这是因为形参和实参是两个不同的存储单元。
由以上调用过程可知,函数的调用必须在函数的声明之后。只有在声明之后,系统编译时才能识别到当前调用的是函数。
若被调用函数的定义在调用函数之前,则不用进行声明。因为函数定义时,系统以知道了这个函数的存在。
函数的声明与定义的第1行基本相同,只是函数的声明多出了“;”号。
函数的声明是为了方便函数调用时,对其合法性进行检查。函数声明的是函数的原型
函数的定义是对函数功能的确定。函数的定义显然不在声明部分的范围内。
数组元素是可以作为函数的实参的,但数组元素不能作为函数的形参。
因为形参的存储单元是函数被调用时临时分配的,而数组是一个整体,在内存中占一串连续的存储单元,所以形参不可能为单个数组元素分配存储单元。但数组元素的值是可以单独分配存储单元进行存储的(单个的数组元素与单个变量的概念是一样的)。所以数组元素可以作为函数的实参。
函数的数组名即可以作为函数的实参,又可以作为函数的形参。
形参数组可以不指定大小,在定义数组是在数组后跟一个空的方括号即可。
如:float average(float array[])
定义性声明:简称定义,需要建立存储空间。
引用性声明:简称声明,不需要建立存储空间。
int a; //既是定义,又是声明 extern a; //只是声明
-
按作用域分
-
按变量的生存期分
-
从变量值存放的位置来分
-
局部变量
函数内部定义的变量、复合语句内定义的变量、形参都是局部变量。
函数内部定义的变量,只在本函数范围内有效;复合语句内定义的变量,只在本复合语句范围内有效;形参是另一种形式的函数内部变量。 -
全局变量
在函数外部定义的变量称为外部变量,外部变量是全局变量。
全局变量的有效范围是从定义变量的位置开始,到本源文件结束。 -
不建议频繁使用全局变量的原因
- 全局变量全程都占据存储单元
- 是函数的通用性降低。在使用改函数功能的同时,还必须考虑到它所调用的函数外的全局变量。不易迁移
- 降低了程序的清晰性
注:全局变量与局部变量重名时,在局部变量范围内,会使用局部变量。
动态存储和静态存储(生存期)-
静态存储
程序运行期间由系统分配固定的存储空间,程序运行的整个过程变量值都是存在的。
全局变量全部存放在静态存储区中。 -
动态存储
程序运行期间根据需要进行动态的分配存储空间,函数调用结束后才存储单元马上释放,函数值就不存在了。
形参、函数中的自动变量都存放在动态存储区中。
C语言中,每一个变量和函数都有两个属性:数据类型和数据的存储类别。数据类型即整型、浮点型等;数据的存储类别指数据在内存中存储的方式。
C的存储类别包括4种:自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)
-
自动变量(auto变量)
函数中的局部变量,若不专门声明为static(静态)存储类别,都是动态分配存储空间的。在调用该函数时,系统会自动分配存储单元,函数调用结束后就自动释放这些存储单元。因此这类局部变量被称为自动变量。自动变量的关键字auto是可以省略不写的。 -
静态变量(static变量)
- 局部变量
若希望局部变量的值在函数调用后依然保留,即不释放存储单位。可用关键字static进行声明,使其变为静态局部变量。
- 静态局部变量属于静态存储类别,函数调用后不释放存储单元
- 静态局部变量只赋初值一次,以后每次调用函数不在重新赋初值,而是保留上一次函数调用结束时的值。
- 虽然静态局部变量在函数调用结束后仍存在,但其他函数是不能引用它的。因为它是局部变量,作用域只局限于本函数。
- 全局变量
全局变量都是存放在静态存储区中的,因此它们的生存期是固定的。但全局变量的作用域是不固定的。一般来说,外部变量的作用域是从变量的定义处开始,到本程序文件的末尾。但通过关键字的定义可将变量的作用范围扩展。- 在一个文件内扩展外部变量的作用域(extern)
外部变量遵循先定义、后使用的原则。若想在定义之前就引用外部变量,则应在引用前用关键字extern对该变量作”外部变量声明“,将该外部变量的作用域扩展到此位置。 - 将外部变量的作用域扩展到其他文件(extern)
若程序包括多个文件,某两个文件想共同引用同一个外部变量,则可以:在任一文件中定义外部变量A,在另一文件中用关键字extern对该变量进行”外部变量声明“ - 将外部变量的作用域限制在本文件中(static)
若希望某些外部变量只能被本文件引用,则使用关键字static进行声明,称为”静态外部变量“
- 在一个文件内扩展外部变量的作用域(extern)
- 局部变量
-
寄存器变量(register变量)
一般情况下,变量(静态存储方式和动态存储方式)的值都是存放在内存中的。如果一些变量使用频繁,为提高执行效率,允许将局部变量的值放在CPU中的寄存器中。用关键字register声明,被称为寄存器变量
-
内部函数
该函数只能被本文件中的其他函数所调用,由关键字static声明,又称为静态函数
static 类型名 函数名(形参表); -
外部函数
该函数可供其他文件中的函数所调用,由关键字extern声明。函数本质上都是外部的,所以extern可以省写
**extern 类型名 函数名(形参表); **
输出以下结果:
#include例7.2找最大值int main() { void print_star(); //函数的声明,声明函数的原型 void print_message(); print_star(); //函数的使用,使用print_star函数,输出*号 print_message(); //使用print_message函数,输出信息 print_star(); return 0; } void print_star() //函数的定义,定义函数功能 { printf("********************n"); } void print_message() { printf("How do you do!n"); }
输入两个整数,要求输出其中值较大者。
#include例7.3返回值类型自动转换int main() { int max(int x, int y); //函数声明,告诉编译系统max为有两个参数的函数 int a, b, c; printf("请输入两个整数:n"); scanf("%d%d", &a, &b); c = max(a,b); //使用函数max比较两个数中的较大值 printf("最大值为:%d", c); return 0; } int max(int x, int y) //定义max函数,max函数有两个参数,且有返回值,返回值为int整形 { int z; //局部变量,临时分配存储空间 z = x>y ? x : y; //将x,y中的较大值,赋值给z return z; //返回z的值,释放临时存储空间 }
同上,求最大值
#includeint main() { int max(float x,float y); float a, b; float c; printf("请输入两个数:n"); scanf("%f%f", &a, &b); c = max(a,b); printf("最大值为:%fn", c); return 0; } int max(float x,float y) //max函数的参数为float浮点型,返回值为int整型 { float z; z = x>y ? x : y; return z; //z虽为float浮点型,但max函数为int整型 } //所以z的值会由float转换为int,舍弃小数点后的数
运行结果为:
求两个实数的和
#includeint main() { float add(float x, float y); //声明函数,让编译程序知道函数的相关信息 float a, b, c; printf("输入两个实数:n"); printf("a = "); scanf("%f", &a); printf("b = "); scanf("%f", &b); c = add(a,b); //调用函数,利用函数功能求两个数的和 printf("两个实数的和为:%fn", c); return 0; } float add(float x, float y) //定义函数,定义函数的具体功能 { float z; z = x+y; return z; }
运行结果为:
输入4个整数,找出其中最大的数
#includeint main() { int max4(int a, int b, int c, int d); //max4函数,求四个中的最大值 int a, b, c, d, max; printf("请输入4个整数:na = "); scanf("%d", &a); printf("b = "); scanf("%d", &b); printf("c = "); scanf("%d", &c); printf("d = "); scanf("%d", &d); printf("n"); max = max4(a, b, c, d); //调用max4函数,将最大值赋值给变量max printf("4个整数中的最大值为:%d", max); return 0; } int max4(int a, int b, int c, int d) //max4函数,求四个整数的最大值 //max4函数通过嵌套了max2函数来实现它的功能,即两两比较最大值 { int max2(int a, int b); //max2函数,求两个整数的最大值, int m; m = max2(a,b); m = max2(m,c); m = max2(m,d); return m; } int max2(int a, int b) //max2函数,求两个整数的最大值,被嵌套在了max4函数中 { if(a >= b) return a; else return b; }
优化后:
#includeint main() { int max4(int a, int b, int c, int d); //max4函数,求四个中的最大值 int a, b, c, d, max; printf("请输入4个整数:na = "); scanf("%d", &a); printf("b = "); scanf("%d", &b); printf("c = "); scanf("%d", &c); printf("d = "); scanf("%d", &d); printf("n"); max = max4(a, b, c, d); //调用max4函数,将最大值赋值给变量max printf("4个整数中的最大值为:%d", max); return 0; } int max4(int a, int b, int c, int d) //max4函数,求四个整数的最大值 //max4函数通过嵌套了max2函数来实现它的功能,即两两比较最大值 { int max2(int a, int b); //max2函数,求两个整数的最大值, return max2(max2(max2(a, b), c), d); } int max2(int a, int b) //max2函数,求两个整数的最大值,被嵌套在了max4函数中 { return(a>=b ? a : b); }
运行结果如下:
有5个学生坐在一起,问第5个学生多少岁,他说比第4个学生大2岁。问第4个学生,他说比第3个学生大2岁。问第3个学生,比第2个学生大2岁。问第2个学生,比第1个学生大2岁。最后问第1个学生,他说10岁。问第5个学生多大。
数学公式表述如下:
| n=1 | n>1 |
|---|---|
| age(n)=10 | age(n)=age(n-1)+2 |
#include例7.7递归2int main() { int age(int n); printf("第5个孩子的年龄为:%dn", age(5)); return 0; } int age(int n) { int c; if(n == 1) //当n=1时,年龄为10,此为基线 c = 10; else c = age(n-1)+2; //当n>1时,年龄时前一个孩子的年龄加2 return c; }



