570 likes | 769 Views
8 函数. 8.1 C 程序模块. 一、 C 程序模块. 一个 C 程序可由一个 main( ) 函数和多个其它函数构成。. 其它函数指的是:. 系统函数 由系统提供,放在头文件中. 自编函数 由程序设计人员编写. main. funa. funb. func. fund. funx. funy. 二、函数的调用. 如:. P137. 所有的函数都 具有两种特征:. 返回值. 参数. ( 返回值和参数都是可缺省的 ). 8.2 库函数. 一、库函数简介.
E N D
8.1 C程序模块 一、C程序模块 一个C程序可由一个main( )函数和多个其它函数构成。
其它函数指的是: 系统函数由系统提供,放在头文件中 自编函数由程序设计人员编写
main funa funb func fund funx funy 二、函数的调用 如: P137
所有的函数都 具有两种特征: 返回值 参数 (返回值和参数都是可缺省的)
8.2 库函数 一、库函数简介 系统自带的标标准库函数根据不同的功能作用放在不同的头文件中。
如:stdio.h用于标准输入/输出 math.h用于数学计算 ctype.h用于字符处理 string.h用于字串处理 time.h用于时间/日期的处理 dir.h用于控制目录和路径 graphics.h用于图形操作 dos.h 用于接口处理 bios.h
二、库函数的作用 使程序更具有“ 独立性”和“ 可移植”性。 使用时只需在程序的开头加上一条语句: #include <.h> 根据使用的函数来确定 使程序具有“ 模块化”。
例1:求两个浮点型数值x/y的余数。 (注意:不能写成3.6%1.7) #include <stdio.h> #include <math.h> main( ) { float x, y, z; scanf("%f%f", &x, &y); z=fmod(x, y); printf(" z=%f", z); }
8.3 自定义函数 一、自定义函数的作用 使程序具有“ 积木”功能。(模块化) 使程序具有“ 重构”功能。
二、 函数的定义及调用 定义 [存储类型符] [返回值类型符] 函数名([形参表列]) 形参说明 { 说明部分 语句 }
调用 变量名=函数名([实参表列]); (变量名的类型必须与函数的返回值类型相同) 函数名([实参表列]);
三、函数声明 一般情况下,函数被调用之前必须要有函数声明。 (函数声明的意义在于提供函数原型) 函数声明的格式: [返回值类型符] 函数名(形参类型);
四、举例 例1:求二个数中的最大值 int max (x, y) int x, y; {int z; z=x>y? x:y; return (z); } 或:int max (int x, int y) {int z; z=x>y? x:y; return (z); } 用return语句,返回函数的值。
通过函数调用求二个数中的最大值: #include <stdio.h> int max (int, int); /*函数原型*/ main( ) { int a, b, t; scanf("%d%d", &a, &b); t=max(a, b); /*函数调用*/ printf("value of maximize is: t=%d",t); } int max(int x, int y) /*函数定义*/ { int z; z=x>y? x:y; return(z); }
例2:求二实数之和 #include <stdio.h>float add( );/*函数说明*/main ( ) { float a, b, c;scanf("%f, %f",&a, &b);c=add(a, b);/*函数调用*/ printf ("sum= %f";c); } float add( float x, float y); /*函数定义*/ { float z; z=x+y; return z; } 若函数的定义放在main( )函数之前可省略函数说明。
例3:求二实数之和(将例2程序改写如下:) #include <stdio.h>float add( float x, float y); /*函数定义*/ { float z; z=x+y; return z; } main ( ) { float a, b, c;scanf(“ %f, %f”,&a, &b);c=add(a, b); /*函数调用*/ printf ("sum= %f";c); }
单向 形参。 调用时:实参值 传递 五、自定义函数中的几个重要特征 1. 形参与实参 实参:出现在调用函数中, 形参: 出现被调用函数中。 函数被调用时,临时分配单元给形参,调用完毕, 这些单元被释放。
注: 实参可为表达式,只传递表达式的值。 实参、形参类型一致。 可在形参表列中对形参说明。
2. 函数返回 return; 函数无返回值 return 表达式的值; 或 return 变量的值; 通过return语句将流程返回主调函数。
3. 函数名 要选择一个简洁的有意义的名字作为函数名。 从函数名可以反映出函数的功能。 P139 例5.7,例5.8
8.4 数组作为函数的参数 一、数组元素作为函数的参数 由于数组元素的性质与相同类型的简单变量的性质完全相同,因此,把数组元素作为函数的参数也和简单变量一样。 使用方法:把数组元素作为函数的实参。 作用:传值。
例2:将数组元素作为函数的实参数 #include <stdio.h> #include <conio.h> main( ) { float b[3]; float ave; b[0]=21.3; b[1]=b[0]/3; b[2]=8.2; printf(" b[0]=%4.1f\t b[1]=%4.1f\t b[2]=%4.1f\n",b[0],b[1],b[2]); float Expfun1(float a,float b,float c); /*函数说明*/ ave=Expfun1(b[0],b[1],b[2]); /*函数调用*/ printf(" ave=%4.1f\n",ave); printf(" b[0]=%4.1f\t b[1]=%4.1f\t b[2]=%4.1f\n",b[0],b[1],b[2]);
getch(); } float Expfun1(float a,float b,float c) /*函数定义*/ { float sum,aver; sum=a+b+c; a=a+5.5; b=b+5.5; c=c+5.5; aver=sum/3.0; printf(" a=%4.1f\t b=%4.1f\t c=%4.1f\n",a,b,c); return (aver); }
程序运行结果: b[0]=21.3 b[1]= 7.1 b[2]= 8.2 /*调用前*/ a=26.8 b=12.6 c=13.7 ave=12.2 b[0]=21.3 b[1]= 7.1 b[2]= 8.2 /*调用后值未变*/
1. 数组名的作用 数组名代表的是数组的起始地址; 也就是第1个元素的地址。
2. 把数组名作为函数参数的规则 使用数组名作为函数的参数时,形参和实参必须是同一类型的数组名,系统采用地址传送方式进行数据传递,即实参的首地址传递给形参的首地址,实参与形参共享相同的数据单元。 使用方法:函数的实参和形参都必须是数组名。 作用:传址。 (可以在函数中修改数组元素的值。)
例1:将数组名作为函数的形参和实参 #include <stdio.h> #include <conio.h> main( ) { float Expfun2(float a[4]); /*函数说明*/ float s[4]={88.5,90.5,70,71}; float ave; printf(" s[0]=%4.1f\t s[1]=%4.1f\t s[2]=%4.1f\t s[3]=%4.1f\n",s[0],s[1],s[2],s[3]); ave=Expfun2(s); /*函数调用*/ printf(" ave=%4.1f\n",ave); printf(" s[0]=%4.1f\t s[1]=%4.1f\t s[2]=%4.1f\t s[3]=%4.1f\n",s[0],s[1],s[2],s[3]); getch(); }
float Expfun2(float a[4]) /*函数定义*/ { float sum,aver; sum=a[0]+a[1]+a[2]+a[3]; aver=sum/3.0; a[0]=a[0]/10; a[1]=a[1]/10; a[2]=a[2]/10; a[3]=a[3]/10; printf(" a[0]=%4.1f\t a[1]=%4.1f\t a[2]=%4.1f\t a[3]=%4.1f\n",a[0],a[1],a[2],a[3]); return (aver); }
程序运行结果: s[0]=88.5 s[1]=90.5 s[2]=70.0 s[3]=71.0/*调用前*/ a[0]= 8.9 a[1]= 9.1 a[2]= 7.0 a[3]= 7.1/*调用中*/ ave=106.7 s[0]= 8.9 s[1]= 9.1 s[2]= 7.0 s[3]= 7.1/*调用后值改变*/
s[0] a[0] 88.5 s[1] a[1] 90.5 s[2] a[2] 70.0 s[3] a[3] 71.0 运行结果分析: 显然,数组s元素的值在调用前后生了变化,数组s和a共用一段内存单元: P43 例5.10, 例5.11,例5.12
三、多维数组名作为函数参数 • P148 例5.14
8.5嵌套调用 • P151 例5.16,例5.17,例5.18
8.6 递归调用 一、递归的特点 一个问题能够成为递归必须具备的条件是: 后一部分与原始问题类似 后一部分是原始问题的简化
二、程序中的递归方式 1. 直接递归调用:函数直接调用本身 2. 间接递归调用:函数间接调用本身
直接调用: int f(x) int x; { int y, z; z=f (z); } 间接调用: int f1 (x) int x; { int y, z; z=f2 (y); } int f2 (t) int t; { int a, b; a=f1 (b); } 以下表示了递归的概念.
1 (n=0, 1) n(n–1)! (n>1) n!= 显然:上述例子会无限递归 (无限执行)。所以, 在递归调用时都必须有条件限制。 当条件成立, 调用递归, 否则结束。 例1:求n! 1. 从数学上定义
2. 程序: #include <stdio.h> long fac(int n) /*函数定义, 计算n!*/ { long f;if (n<0) printf("input error!\n");elseif (n= = 0 ¦¦n= =1) f =1;else f =nfac(n –1); return (f); }
main ( ) { int n; long y; printf("input a integer! ") scanf ("%d", &n); y=fac(n); /*函数调用, 计算n!*/ printf("%d!=%15ld", n, y); }
3. 执行过程: 设:输入 5 (n=5) 第1次调用:y=fac(5) —— 返回:y=5fac(4) 第2次调用:y=5*4fac(3) 第3次调用:y=5*4*3fac(2) 第4次调用:y=5*4*3*2fac(1) 第5次调用:y=5*4*3*2*1*fac(0) P173
8.7 标识符的作用域 标识符可以具有四种作用域。 函数作用域 文件作用域 块作用域 函数原型作用域 (作用域: 有效范围) 可根据标识符的作用域区分局部变量和全局变量。
一、局部变量 凡在函数(含main 函数)内部定义的变量称为局部变量。 局部性: 局部变量仅在函数内部有效。
1. 不同的函数可有同名同类型的变量,它们占不同的内存单元, 互不影响。 2. 形参为局部变量。 3. 在复合语句中可定义仅在复合语句中有效的临时变量。 P159 例5.21,例5.22
二、全局变量 一个源文件中, 在所有函数之外定义的变量为全局变量。 有效性:自定义位置开始至文件结尾全部有效。
例: int p=1, q=5; float f1(a) int a; {int b, c; } char c1, c2; p,q的作用范围 char f2(x,y) int x, y; { int i, j;} main ( ) { } c1, c2的作用范围
注意 1. 全局变量所作用到的函数,相当于这些函数的公共变量。当一个函数对其值进行改变后,另一个函数使用该变量的值亦相应改变。好处:函数之间值传递。 2. 不要随意使用全局变量。一是始终占据内存单元;二是由于函数依赖于外部定义的变量,减少了通用性。
3.不在作用域内函数。若使用全局(外部)变量,需在函数体内加上extern保留字。3.不在作用域内函数。若使用全局(外部)变量,需在函数体内加上extern保留字。 4.全局和局部变量同名时,局部变量有效。
例: float f1 (x) int x; {extern int a, b; } int a=0; b= –1 main ( ) { } a, b作用域 P162 例5.24 例8.15
8.8 变量的存储类型 一、标识符的属性 一个标识符的属性除了前面已讲过的基本属性外,还具有一些其它的属性: 存储类别 存储期
二、存储类别 1. 存储类型和存储期 自动型 (auto) 自动存储期 寄存器型(register) 外部型(extern) 静态存储期 静态型(static)