第八章函数 重点 1、了解模块化程序设计的思想 2、熟悉掌握函数的使用 3、了解变量的作用范围 [例1]函数调用 main i printf( This is a test! n") p print message printstarO printstarO printf((“************n3); print message printf(" How do you do!n); 81函数( function)介绍 说明: 1.一个源程序文件有一个或多个函数组成 2.一个C程序可以有多个源程序文件组成。 3.任何C程序都从main函数开始执行,当main的最后一条指令 执行完,程序结束 4.所有函数都是独立的,可以互相调用,main不能被调用。 5.函数分为标准函数和用户自定义函数 6.函数分为无参函数和有参函数。 为什么要ⅲ nclude文件? pint, scanfo, putchar o: getchar, puts, gets都在 stdio h中 8.2函数定义及函数声明 1.函数定义 (1).无参数函数的定义 类型标识符函数名()
第八章 函 数 重点: 1、 了解模块化程序设计的思想 2、 熟悉掌握函数的使用 3、 了解变量的作用范围 [例 1:] 函数调用 main() { printf("This is a test!\n"); printstar(); print_message(); printstar(); } printstar() { printf(“* * * * * * * * * * * * \n”); } print_message() { printf(“ How do you do!\n”); } 8.1 函数(function)介绍 说明: 1. 一个源程序文件有一个或多个函数组成。 2. 一个 C 程序可以有多个源程序文件组成。 3. 任何 C 程序都从 main 函数开始执行,当 main 的最后一条指令 执行完,程序结束. 4. 所有函数都是独立的,可以互相调用,main 不能被调用。 5. 函数分为标准函数和用户自定义函数。 6. 函数分为无参函数和有参函数。 为什么要 include 文件? printf();scanf(),putchar();getchar();puts();gets()都在 stdio.h 中。 8.2 函数定义及函数声明 1.函数定义 (1). 无参数函数的定义 类型标识符 函数名( )
(声明部分 语句 (2).有参数函数的定义 类型标识符函数名(形式参数表列) 声明部分 语句 形式参数表列:对形式参数的说明;有两种方法: ① int max(intx,inty) 函数体; ② int max(x,y) Int x,y; 函数体; 注意:在①中xy的数据类型一致,也不能写成 int max( Intx,y) 的型式 (3)可以有空函数 void函数名(参数) 2.函数参数及函数的值 (1)形参和实参 形参:在函数定义时,函数名括号后面的变量名。 实参:在函数被子调用是,函数名括号后面的表达式 (2)调用函数和被调用函数 (3)函数的值 例2:求一个整数的绝对值 int absolute value(int x) i return(X>0=? X:-X) maino i int x,y printf("please input a int x=); scanf(" %d”,&x); y=value(x); printf("In%d absolute is %dn x,y) (4)说明: ①实际参数可以是变量、常量、表达式,它们的值传给形式参 数。实参对形参传递的是值
{ 声明部分 语句 } (2). 有参数函数的定义 类型标识符 函数名(形式参数表列 ) {声明部分 语句 } 形式参数表列:对形式参数的说明;有两种方法: ① int max(int x , int y) { 函数体; } ② int max(x , y) int x,y; { 函数体; } 注意:在①中 x,y 的数据类型一致,也不能写成 int max(int x,y) 的型式。 (3) 可以有空函数 void 函数名( 参数 ) 2.函数参数及函数的值 (1)形参和实参 形参:在函数定义时,函数名括号后面的变量名。 实参:在函数被子调用是,函数名括号后面的表达式。 (2) 调用函数和被调用函数 (3)函数的值。 例 2: 求一个整数的绝对值 int absolute_value(int x) { return(X>0=? X: -X); } main() { int x,y; printf(“please input a int x=”); scanf(“%d”,&x); y=value(x); printf(“\n %d absolute is %d\n”,x,y); } (4)说明: ① 实际参数可以是变量、常量、表达式,它们的值传给形式参 数。实参对形参传递的是值;
②形参在未调用时,并没有分配到内存单元,只有被子调用 时才分配内存单元,调用完后释放内存单元 ③实参与形参的个数、类型要匹配 ④实参与形参是自左向右一一配对的 ⑤形参在函数中被改变并不影响实参的值。 B] 3: float max( float x, floaty, float z) float t t=t>z?t:z return(t) ma i float x, y, z, maxvale printf("please input ax, y, z: ) scanf( %of%of%of, &x, &y, &z) maxvale=max(x, y, z) printf(" In the max is %fn,, max); 3函数的返回值 (1)若要从函数中返回一个值,在函数中要用 return语句; 格式: return(表达式 return 程序执行到 return语句时就退出被调用的程序,返回到被调 用的语句处。 例. void sp(intn) i int I; for(1=0; K=0) float ix(float x) i if (x<0 return(x*x-x+1) eise return(xx*x+x+3) main(
② 形参在未调用时,并没有分配到内存单元,只有被子调用 时才分配内存单元,调用完后释放内存单元。 ③实参与形参的个数、类型要匹配。 ④实参与形参是自左向右一一配对的。 ⑤形参在函数中被改变并不影响实参的值。 例 3:float max(float x,float y,float z) {float t; t=x>y ? x : y; t=t>z?t : z; return(t); } main() { float x,y,z,maxvale; printf(“please input a x,y,z :”); scanf(“%f%f%f”,&x,&y,&z); maxvale=max(x,y,z); printf(“\n the max is %f\n”, max); } 3.函数的返回值 (1)若要从函数中返回一个值,在函数中要用 return 语句; 格式:return ( 表达式); return; 程序执行到 return 语句时就退出被调用的程序,返回到被调 用的语句处。 例. void spc(int n) { int I; for ( I=0;I=0) float fx(float x) { if (x<0) return(x*x-x+1); else return(x*x*x+x+3); } main() { float x,y;
printf( please input ax ) scanf( %of, &x) y=fx(x) printf(n whten x is %f, x) printf(" n the y is %fy); 4.对被调用函数的说明 (1)一个函数中调用另一函数需具备的条件: ①被调用的函数必须存在 ②如果使用库函数,还应用# include命令调用头文件 (2)如果用户自定义的函数,一般还应在主调函数中对被调函 数的返回值的类型说明。型式为: 类型标识符被调用函数名() 例5: main float max(),/*对被调函数的说明,也可表示为foat* /*max(float x, float y, float z)/ float*/ /*max(float, float, float * float x,y printf("please inputax, y, z: ) scanf( %of%of%f, &x, &y, &z) printf( n the max is %fn", max(x, y, z); float max(float x, float y, float z) float t. y?X y return(t): (3)以下几种情况可以不在调函数前对被调用函数作类型说 明 ①如果数的值(函数返回的值)是整型或字符型,系统对 它们自动按整型说明 ②如果被调用函数的定义出现在主调函数之前,可以不必 加以说明。 ③如果已在所有函数定义之前,在文件的开头,在函数的 外部已说明了函数类型,则在各调用函数中不用再说明。 83函数调用 831函数调用的一般形式 1.函数名(实参表列)
printf(“please input a x :”); scanf(“%f”,&x); y=fx(x); printf(“\n whten x is %f”,x); printf(“\n the y is %f”,y); } 4.对被调用函数的说明 (1)一个函数中调用另一函数需具备的条件: ①被调用的函数必须存在。 ②如果使用库函数,还应用#include 命令调用头文件; (2)如果用户自定义的函数,一般还应在主调函数中对被调函 数的返回值的类型说明。型式为: 类型标识符 被调用函数名( ); 例 5: main() { float max( ); /*对被调函数的说明,也可表示为 float*/ /*max(float x,float y,float z) 及 float*/ /*max(float,float,float )*/ float x,y,z; printf(“please input a x,y,z :”); scanf(“%f%f%f”,&x,&y,&z); printf(“\n the max is %f\n”, max(x,y,z)); } float max(float x,float y,float z) {float t; t=x>y ? x : y; t=t>z?t : z; return(t); } (3)以下几种情况可以不在调函数前对被调用函数作类型说 明。 ①如果数的值(函数返回的值)是整型或字符型,系统对 它们自动按整型说明。 ②如果被调用函数的定义出现在主调函数之前,可以不必 加以说明。 ③如果已在所有函数定义之前,在文件的开头,在函数的 外部已说明了函数类型,则在各调用函数中不用再说明。 8.3 函数调用 8.3.1 函数调用的一般形式 1.函数名(实参表列)
实参表列的实参与实参之间用逗号隔开,实参可为表达式, 实参的个数要与形参一一对应 2.函数在程序中的位置。 ①作为一般语句。 Printf ②作为一个表达式的一部份。C=2*max(a,b) ③作为另一个函数的参数。M=max(a,max(bc) 832函数的嵌套调用 在一个函数中调用一函数,在被调函数中又调用另一函数。 ●函数中调用其它函数叫函数的嵌套 ◆C中函数的定义是平行的,除了main以外,都可以互相调用 函数不可以嵌套定义。 main a 调a调b 8.3.3函数的递归调用 函数自己调用自己,即函数的递归调用,递归调用可以使程序简 洁、代码紧凑,但要牺牲内存空间作处理时的堆栈。 要点:在函数中要有终止递归调用的i语句 例6:如要求一个n(n的阶乘)的值可用下面递归调用: n- nf(n-1)n≠1 # include“ stdio. h main( i long mul( int n); int m printf("Calculate n!n=?n") scanf("%od",&m); *键盘输入数据*/ printf("o%dl=%ldn",m,mu(m)/*调用子程序计算并输出* getcho long mul( int n)
实参表列的实参与实参之间用逗号隔开,实参可为表达式, 实参的个数要与形参一一对应。 2.函数在程序中的位置。 ①作为一般语句。 Printf(); ②作为一个表达式的一部份。C=2*max(a,b); ③作为另一个函数的参数。 M=max(a,max(b,c)); 8.3.2 函数的嵌套调用 在一个函数中调用一函数,在被调函数中又调用另一函数。 函数中调用其它函数叫函数的嵌套。 C 中函数的定义是平行的,除了 main 以外,都可以互相调用。 函数不可以嵌套定义。 8.3.3 函数的递归调用 函数自己调用自己, 即函数的递归调用, 递归调用可以使程序简 洁、代码紧凑, 但要牺牲内存空间作处理时的堆栈。 要点:在函数中要有终止递归调用的 if 语句。 例 6:如要求一个 n!(n 的阶乘)的值可用下面递归调用: 1 n=1 f(n)= n*f(n-1) n≠1 #include “stdio.h” main() { long mul( int n); int m; printf("Calculate n! n=?\n"); scanf("%d", &m); /*键盘输入数据*/ printf("%d!=%ld\n", m, mul(m));/*调用子程序计算并输出*/ getch(); } long mul( int n)
lo p=n"mul(n-1) /*递归调用计算n!* p return(p); /*返回结果* maino 求fac(4)nf-24 求fac(3)24 fac( 求tc(2)62m 求fac(1) fac( 返回值1 fac(n) 84数组作为函数参数 数组元素可以做函数实参,其用法与变量相同。数组名也可以 做实参和形参,传递的是整个数组 1.数组元素做函数实参 数组元素作函数的实参,与用变量做实参一样,是单向传递, 即“值传送”方式 例7比较两个数组的对应元素,比较过程在函数中完成,计较结 果在主函数中输出 maino {inta[0],b[10],in=0,m=0,k=0, printf((输入数组ain") for(ⅰ=0:i<10:i++ scanf("%d", &aiD; printf((输入数组b:n"); for(i=0;1<10;i++ scanf("%d", &biD for(i=0<10;i++) {i( arge(al,b[==1川n+;
{ long p; if(n>1) p=n*mul(n-1); /*递归调用计算 n!*/ else p=1; return(p); /*返回结果*/ 8.4 数组作为函数参数 数组元素可以做函数实参,其用法与变量相同。数组名也可以 做实参和形参,传递的是整个数组。 1.数组元素做函数实参。 数组元素作函数的实参,与用变量做实参一样,是单向传递, 即“值传送”方式。 例 7.比较两个数组的对应元素,比较过程在函数中完成,计较结 果在主函数中输出. main() { int a[10],b[10],i,n=0,m=0,k=0; printf(“输入数组 a:\n"); for (i=0;i<10;i++) scanf("%d",&a[i]); printf(“输入数组 b:\n"); for (i=0;i<10;i++) scanf("%d",&b[i]); for (i=0;i<10;i++) { if(large(a[i],b[i])==1)n++;
if(large(a[b[)≥=0m++; pint(a>b%次na=b%d次nab%d次n"nmk); large(int x, int y) f int flag; if(x>y)flag=l; else if(xb4次 a=b1次 a float average( float array[) maino i float score[10),aver; int 1 printf("input 10 scores: n"); forli=0;<10;H++) scanf("%f”,& scorel) printf("%n); aver=average(scor ) printf(average score is %5.2f", aver); float average( float array[loD
else if(large(a[i],b[i])==0)m++; else k++; } printf(“a>b%d 次\na=b%d 次\nay) flag=1; else if(xb 4 次 a=b 1 次 a float average ( float array[10]); main() { float score[10],aver; int i; printf("input 10 scores:\n"); forIi=0;I<10;I++) scanf("%f",&score[I]); printf("%\n"); aver=average(scor); printf(average score is %5.2f",aver); } float average ( float array[10]);
i int i; float aver, sum=arraylo for(i=1;i void f( void) main i int x printf("x in maino is %dIn,X) f0; printf( x in main( is still %od n, x) void f( void) int x X=100 printf(" the x in fO is %dn, x) 说明:不同函数定义的变量名可以相同,它们分配的内存单元 不同,是不同意义的变量 2.全局变量 全局变量是指在所有函数之外说明的变量,它在整个程序内部 者是"可见的",可以被任何一个函数使用,并且在整个程序的运行中 都保留其值。习惯上通常在程序的主函数前说明。 例10 #include *定义全程变量* void f1(intx, float y);,/*子函数说明* void f2(void) /*子函数说明*
{ int i; float aver,sum=array[0]; for(i=1;i void f(void); main() { int x; x=10; printf(“x in main() is %d\n”,x); } f(); printf(“x in main() is still %d \n”,x); } void f(void) {int x; x=100; printf(“the x in f() is %d\n”,x); } 说明:不同函数定义的变量名可以相同,它们分配的内存单元 不同,是不同意义的变量。 2.全局变量 全局变量是指在所有函数之外说明的变量, 它在整个程序内部 者是"可见的", 可以被任何一个函数使用, 并且在整个程序的运行中 都保留其值。习惯上通常在程序的主函数前说明。 例 10: #include int test; /*定义全程变量*/ void f1(int x, float y); /*子函数说明*/ void f2(void); /*子函数说明*/
maino test =5 *给全程变量赋值* f(20,5.5) /*调用有形式参数的子函数f1O /*test的值变成115*/ f20, /*调用f2O,test的值变为1150*/ void fl(int x, float y) float z, /*z定义为局部变量* /*计算* test=test+z void f2(void) nt count=10 *定义局部变量并初始化* test=test*count 例11 int a=3. b=5 maino dvoid swap(void) printf("a=%od, b=%dn",a, b); swap(; printf("a=%d, b=%d\n", a, b) void swapO i int t t=a: a=bb=t 852变量的存储属性 Turbo C2.0支持四种变量存储类型。说明符如下 static extern register l、auto auto称为自动变量.自动变量是在函数执行时分配存储单元,函 数执行完后释放其占有存储单元。在编译时,自动变量是一个不确定 的值。 格式: auto int b,c=3 auto可以省略。 2、 static static称为静态变量。静态变量在未初始化赋值时,有一个确 定的值(nt型值为0,foat型值为00,char型为0).根据变量
main() { test=5; /*给全程变量赋值*/ f1(20, 5.5); /*调用有形式参数的子函数 f1()*/ /*test 的值变成 115*/ f2(); /*调用 f2(), test 的值变为 1150*/ } void f1(int x, float y) { float z; /*z 定义为局部变量*/ z=x*y; /*计算*/ test=test+z; } void f2(void) { int count=10; /*定义局部变量并初始化*/ test=test*count; } 例 11: int a=3, b=5; main() {void swap(void); printf(" a=%d,b=%d\n",a,b); swap(); printf(" a=%d,b=%d\n",a,b); } void swap() { int t; t=a;a=b;b=t; } 8.5.2 变量的存储属性 Turbo C2.0 支持四种变量存储类型。说明符如下: auto static extern register 1、auto auto 称为自动变量. 自动变量是在函数执行时分配存储单元,函 数执行完后释放其占有存储单元。在编译时,自动变量是一个不确定 的值。 格式:auto int b,c=3; auto 可以省略。 2、static static 称为静态变量。静态变量在未初始化赋值时,有一个确 定的值(int 型值为 0,float 型值为 0.0, char 型 为’\0’).根据变量
的类型可以分为静态局部变量和静态全程变量。 (1)静态局部变量 它与局部变量的区别在于:在函数退出时,这个变量始终存在 但不能被其它函数使用,当再次进入该函数时,将保存上次的结果 其它与局部变量一样。 nt fac(n) nt n (static int f-1 f=fn return(f maint printf("%d!=%dIn", i, fac(i); (2)静态全程变量 静态全程变量就是指只在定义它的源文件中可见而在其它源文 件中不可见的变量。它与全程变量的区别是:全程变量可以再说明为 外部变量( extern)被其它源文件使用,而静态全程变量却不能再被 说明为外部的,即只能被所在的源文件使用 3、 extern extern称为外部变量。为了使全局变量除了在定义它的源文件中 可以使用外,还要被其它文件使用。因此,必须将全程变量通知每一 个程序模块文件,此时可用 extern来说明。 例如 文件1为 filel.c 文件2为fle2c nti,j/定义全程变量* extern int I,j/说明将i,j从 文件1中复制过来* char c extern char c;/*将c复制过来* void funcl (int k) func20/*用户定义函数* maino static float k;/*定义静态变量* *5/100 fungI(20),/*调用函数* k=i/1.5 func20 final(ntk)/*用户定义函数* j=k*100
的类型可以分为静态局部变量和静态全程变量。 (1). 静态局部变量 它与局部变量的区别在于: 在函数退出时, 这个变量始终存在, 但不能被其它函数使用, 当再次进入该函数时, 将保存上次的结果。 其它与局部变量一样。 int fac(n) int n; {static int f=1; f=f*n; return(f); } main() {int i; for(i=1;i<=5;i++) printf("%d!=%d\n",i,fac(i)); (2). 静态全程变量 静态全程变量就是指只在定义它的源文件中可见而在其它源文 件中不可见的变量。它与全程变量的区别是: 全程变量可以再说明为 外部变量(extern), 被其它源文件使用, 而静态全程变量却不能再被 说明为外部的, 即只能被所在的源文件使用。 3、extern extern 称为外部变量。为了使全局变量除了在定义它的源文件中 可以使用外, 还要被其它文件使用。因此, 必须将全程变量通知每一 个程序模块文件, 此时可用 extern 来说明。 例如: 文件 1 为 file1.c 文件 2 为 file2.c int i, j;/*定义全程变量*/ extern int i, j;/*说明将 i, j 从 文件 1 中复制过来*/ char c; extern char c; /*将 c 复制过来*/ void func1(int k); func2() /*用户定义函数*/ { main() static float k;/*定义静态变量*/ { i=j*5/100; func1(20);/*调用函数*/ k=i/1.5; func2(); . . . . . . } } func1(int k) /*用户定义函数*/ { j=k*100; }