750 likes | 916 Views
第 8 章 函数. 8.1 概述. 程序结构概念 : 1 )较大的程序应分为 若干个程序模块 ; 2 )每个模块实现单一的特定功能; 3 )由主函数开始执行,主函数调用子函数; 4 )子函数之间可以互相调用。. 说明 :. 1. 一个源文件可由一个或多个函数组成; 2. 一个 源文件 是一个 编译单位 ; 3. 一个 C 程序 由一个或多个 源文件 组成。 4. 从 main() 开始,调用其它函数后, 回到 main() 结束 ; 5. 不能嵌套定义,但可互相调用 。 6. 分类 :
E N D
第8章 函数 8.1 概述 程序结构概念 : 1)较大的程序应分为若干个程序模块 ; 2)每个模块实现单一的特定功能; 3)由主函数开始执行,主函数调用子函数; 4)子函数之间可以互相调用。
说明 : 1. 一个源文件可由一个或多个函数组成; 2. 一个源文件是一个编译单位; 3. 一个C 程序由一个或多个源文件组成。 4. 从 main() 开始,调用其它函数后, 回到 main() 结束 ; 5. 不能嵌套定义,但可互相调用 。 6. 分类 : 1) 标准函数 和 用户自定义函数 ; 2) 无参函数 和 有参函数 。
8.2 函数定义 1. 无参函数的定义 形式:类型标识符 函数名( ) {说明部分 语句 } 例如: main( ) { int a=5,b=9 ; printf(" %d\n " , a*b*b ); } 说明:若不带回函数值,类型标识符也可以不写,无参函数一般用于完成指定的一组操作。
2.有参函数的定义 形式:类型标识符 函数名(形式参数表列) 形式参数说明 {说明部分 语句} 如:int max( x, y ) int x , y; { int z ; z=x>y ? x : y ; return ( z ) ; } 空函数定义形式: 类形标识符 函数名( ) { } 作用:备以后扩充。
8.3 函数参数和函数的值 8.3.1 形式参数和实际参数 形式参数 : 定义函数时,括号中说明的变量名 ; 实际参数 : 调用函数时,括号中给定的表达式 。
main( ) main( ) { int a,b,c; { int a,b,c; scanf ("%d,%d",&a,&b); scanf ("%d,%d",&a,&b); c=max( a ,b ); 函数调用 c=max( a ,b ); printf ("max is %d\n",c); printf ("max is %d\n",c); } int max( x, y ) max( x, y ) 形参说明 int x,y; int x,y; {int z; { int z; z=x>y?x:y; z=x>y?x:y; return (z); return (z); }
说明: 1. 定义函数时,形参不占内存单元 ; 调用函数时,形参才分配内存单元 ; 调用结束后,形参所占内存单元被释放。 2. 实参可以是常量、变量或表达式,但必须有确切的值。 3. 定义函数,必须指明形参类型。 4. 实参与形参类型一致。 5. 实参变量对形参变量的数据传递是“值传递 ”,即单向传递。 6. 可在“形参表列”中说明形参类型。 int max( int x , int y ) { 函数体 }
8.3.2 函数的返回值 说明 : 1. 通过 return 语句获得返回值 ; 2. 定义函数时指定函数返回值的类型;不加类型说明 的,按整型处理。 3. 函数值的类型和 return 语句中表达式的值不一 致时,以函数类型为准。 4. 被调用函数中没有 return 语句时,带回一个不 确定的值。 5. 为了明确表示“不带回值”,可以用“ void ” 定 义 “ 无类型 ”。
看下面例子: main() {float a,b; int c; scanf(“%f,%f”,&a,&b); c=max(a,b); printf(“Max is %d\n”,c); } max(float x,float y) {float z; z=x>y?x:y; return (z)} 运行结果: 1.5,2.5 Max is 2
8. 4 函数的调用 8.4.1 函数调用的一般形式 函数名(实参表列) 说明 : 1.无参函数,括号不能省 ; 2.实参表列中,各实参与形参在 个数、顺序、 类型上一一对应,参数间用逗号分隔。 注意:计算实参时的次序不同。为了提高程序的通用性,一般都写清楚。
int f(int a,int b) { int c; if (a>b) c=1; else if (a= =b) c=0; else c=-1; return (c); } 函数调用发生 函数调用结束 i 5 j 9 i 5 j 9 a,b所占的存储单元被释放 b 9 a 5 main( ) {int i,j,p; scanf("%d%d",&i,&j); p=f(i,j); printf ("%d",p); }
8.4.2 函数调用的方式 调用函数的方式有三种: 函数语句、函数表达式、函数参数。 如:printf("******"); m=max(a,b)*20; printf("%d",max(a,b));
8.4.3 对被调用函数的声明和函数原型 1.被调函数必须存在; 2.用#include命令包含有关库函数; 3.被调用函数一般应在主调函数前定义,这样在主调函数中可以不对调用函数类型进行声明。否则在主调函数中必须对调用函数类型进行声明(整型除外); 4.如果在文件开头,已声明了被调函数类型,则主调函数中不必再作类型声明。
被调用函数声明 例 1: 函数声明的作用是把函数名及函数类型、形参个数及类型通知编译系统,以便在调用该函数时系统按此进行对照检查。 main( ) {float add( ); float a,b,c; ..... } float add(x,y) float x,y; {…} float add(float,float); float add(float x,float y ); 函数定义 函数定义是指对函数功能的确立,包括指定函数名、函数值类型、形参个数及类型、函数体等。它是一个完整、独立的程序单位。
例 2: float add(x,y) float x,y; { float z; z=x+y; return(z); } main( ) { float a,b,c; scanf("%f,%f",&a,&b); c=add(a,b); printf("%f\n",c); } 在主调函数前定义
char let( ); float f( ); int max( ); 例 3: 已在文件 开头声明 main( ) {......} char let(c1,c2) char c1,c2; {......} float f(x,y) float x,y; {......} int max(j,k) float j,k; {......} 定义 let 函数 定义f函数 定义max函数
main( ) { float a; int y(); scanf ("%f",&a); printf ("%d", y(a)); } 1 x>0 y= 0 x=0 -1 x<0 程序举例: float x; 例1:求下列函数的值 scanf("%f",&x); y(x) y(a) int y(float x) { int z; if (x>0) z=1; else if (x<0) z=-1; else z=0; return(z); } a 5 x 5 x
例 2.求5!、16!和27! float jiec(n) int n; { float y=1; int i; for (i=1;i<=n;i++) y=y*i; return (y); } main( ) { float a,b,c; a=jiec(5); b=jiec(16); c=jiec(27); printf ("%f,%f,%f\n",a,b,c); }
例 3.编写函数,判定某数字是否在某正整数中,若在,打印 TRUE,否则打印 FALSE,输出结果在主函数中完成。 main( ) {int m,n; /*判断数字n是否在数m中/ int among(int m,int n); scanf("%d %d",&m,&n); if(among(m,n)) printf("TRUE"); else printf("FALSE"); }
int among(m,n) int m,n; { int k,z=0; do {k=m%10; if (n==k) {z=1; break;} m=m/10; }while(m!=0); return(z); }
例 4.统计 400~499 这些数中 4 这个数字出现的次数,判一个数有几个数字4,用函数实现 。 num(x) int x; { int y,k=0; while (x!=0) {y=x%10; if(y==4) k++; x=x/10; } return(k); } main() {int i,k=0; for(i=400;i<=499;i++) k=k+num(i); printf ("number=%d\n",k); }
例 5. 找出1000之内的所有“完数”,判一个数是否为完数,用函数实现 。 wan(x) int x; { int i,k=0; for (i=1;i<=x/2;i++) if (x%i==0) k=k+i; if (k==x) return (1); else return (0); } main( ) { int i; for (i=1;i<1000;i++) if (wan(i)) printf ("%5d",i); printf ("\n"); }
例 6.求图形的面积 。 #include "math.h" float area1(a,b,c) float a,b,c; { float s,p; p=(a+b+c)/2; s=sqrt(p*(p-a)*(p-b)*(p-c)); return(s); } float area2(d) float d; { float s; s=3.14159*(d/2)*(d/2)/2; return(s); }
main( ) { float a,b,c,s; scanf ("%f%f%f",&a,&b,&c); s=area1(a,b,c)+area2(a)+area2(b)+area2(c); printf ("%f\n",s); }
8.5 函数的嵌套调用 不能嵌套定义函数,可以嵌套调用函数 。 main 函数 { 调用 a 函数 } a 函数 { 调用 b 函数 return(); } b 函数 { return(); }
例 .写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果 。 int lcm(a,b) int a,b; { int r; r=gcd(a,b); return(a*b/r); } int gcd(a,b) int a,b; {int r; do {r=a%b; a=b; b=r;} while (r!=0); return (a); } main( ) { int x,y; scanf ("%d%d",&x,&y); printf ("%d\n",gcd(x,y)); printf ("%d\n",lcm(x,y)); }
8.6 函数的递归调用 在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用 。 递归问题的特点 : 1 . 把一个问题转化为一个新问题,新问题与原问题解法相同 ,只是所处理的对象有所不同,但它们只是有规律的递增或递减 。 2 . 必须有某个终止递归的条件。
例 1. 用递归法求 n! 1 (n=1或n=0) n!= n*(n-1)! (n>1) main( ) { int n; float fac( ); float y; scanf ("%d",&n); if (n<0) printf ("n<0,data error\n"); else { y=fac(n); printf ("%d!=%15.0f",n,y); } } n!=n*(n-1)! (n-1)!=(n-1)*(n-2)! ... 2!=2*1! 1!=1
float fac(n) int n; { float f; if (n==1||n==0) f=1; else f=fac(n-1)*n; return(f); } 以n=4为例,执行过程如下: fac(n) { ... f=fac(1)*2; return (f); } fac(n) { ... f=1; return (f); } fac(n) { ... f=fac(2)*3; return (f); } main( ) { ... y=fac(4); ... } fac(n) { ... f=fac(3)*4; return(f); } 2 1 24 6
1 (n=0) xn = x (n=1) x*xn-1 (n>1) 例 3.求xn (n>0) float f(int x,int n) { float z; if(n==0) z=1; else if (n==1) z=x; else z=x*f(x,n-1); return z; } main( ) { int x,n; float f( ); scanf ("%d%d",&x,&n); printf ("%d %d %f\n",x,n,f(x,n)); }
f(5,4) float f(x,n) int x,n; { float z; if (n==0) z=1; else if (n==1) z=x; else z=x*f(x,n-1); return z; } float f(x,n) int x,n; { float z; if (n==0) z=1; else if (n==1) z=x; else z=x*f(x,n-1); return z; } 5,3 5,1 float f(x,n) int x,n; { float z; if (n==0) z=1; else if (n==1) z=x; else z=x*f(x,n-1); return z; } float f(x,n) int x,n; { float z; if (n==0) z=1; else if (n==1) z=x; else z=x*f(x,n-1); return z; } z=5; 5,2
例 4.用递归方法求N阶勒让德多项式的值,递归公式 为 : 1 (n=0) pn(x)= x (n=1) (( 2n-1) · x · p n-1(x)-(n-1) · p n-2(x)) /n (n>1)
main( ) { float pn(float,int), x,lyd; int n; scanf ("%d %f",&n,&x); lyd=pn(x,n); printf ("pn=%f\n",lyd); } float pn(x,n) float x; int n; { float temp; if (n==0) temp=1; else if (n==1) temp=x; else temp=((2*n-1)*x*pn(x,n-1)-(n-1)*pn(x,n-2))/n; return (temp); }
8.7 数组作为函数参数 1、 数组元素作函数实参 对应的形参为简单变量。 int sushu(x) int x; {int i,k=1; if(x==1) k=0 for(i=2;i<=x/2;i++) if(x%i==0) k=0; return(k); } 例 1:求正整数数组 a[10]中的素数. main( ) { int a[10],i; for(i=0;i<10;i++) scanf("%d",&a[i]); for(i=0;i<10;i++) if(sushu(a[i])) printf("%5d",a[i]); }
例2:求正整数数组a[4][4]中的素数. main( ) { int a[4][4],i,j; for(i=0;i<4;i++) for(j=0;j<4;j++) {scanf("%d",&a[i][j]); if(sushu(a[i][j])) printf("%5d",a[i][j]);} printf("\n"); } main( ) { int a[4][4],i,j; for(i=0;i<4;i++) for(j=0;j<4;j++) scanf("%d",&a[i][j]); for(i=0;i<4;i++) for(j=0;j<4;j++) if(sushu(a[i][j])) printf("%5d",a[i][j]);} printf("\n"); } int sushu(x) int x; {int i,k=1; if(x==1) k=0; for(i=2;i<=x/2;i++) if(x%i==0) k=0; return(k); }
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9] 2、数组名可作函数实参 对应的形参为数组名 说明 : 1. 数组名作函数参数,应在主调函数和被调函数中分别定义数组 ; 2. 实参数组与形参数组类型应一致 ; 3. 实参数组与形参数组大小可以一致也可以不一致 。形参数组可以不指定大小。 4. 数组名作函数参数时,是 “ 地址传送 ”。 a b
例3: 数组 score 存放 10 个学生成绩,求平均成绩 。 main( ) { float score[10],aver,a; float average(float); int i; for (i=0;i<10;i++) { scanf ("%f",&a); score[i]=a;} aver=average(score); printf (" %5.2f",aver); } float average(array) float array[10]; { int i; float aver,sum=0; for (i=0;i<10;i++) sum=sum+array[i]; aver=sum/10; return(aver); } score array
例4 :用选择法对数组中10个整数按升序排序 。 12 3 45 -7 6 17 4 9 2 77 -7 2 3 4 6 9 12 17 45 77 main() { int a[10],i; void sort( ); for (i=0;i<10;i++) scanf ("%d",&a[i]); sort(a,10); for (i=0;i<10;i++) printf ("%5d",a[i]); printf ("\n"); } void sort(array,n) int array[ ],n; { int i,j,k,t; for (i=0;i<n-1;i++) { k=i; for (j=i+1;j<n;j++) if (array[j]<array[k]) k=j; t=array[k]; array[k]=array[i]; array[i]=t; } } a array
例5 :用冒泡法对数组中10个整数按升序排序 。 冒泡法的思路是:将相邻两个数比较,将小的调到前头. 3 1 5 3 第二轮: (j=1) 依此类推经过 j 轮比较 第一轮: (j=0) 1 3 5 3 1 5 5 1 5 每轮比较n-j-1次 6 6 0 比较9次 比较8次 8 6 0 6 6 0 8 for(j=0;j<n-1;j++) -2 8 8 for(i=0;i<n-j-1;i++) 0 8 -2 8 if(a[i]>a[i+1]) -2 9 9 { t=a[i]; a[i]=a[i+1]; a[i+1]=t; } 9 9 4 -2 9 4 9 9 21 21 4 4 21 21
5 3 1 8 6 0 9 -2 21 4 -2 0 1 3 4 5 6 8 9 21 main() { int array[10],i; void sort( ); for (i=0;i<10;i++) scanf ("%d",&array[i]); sort(array,10); for (i=0;i<10;i++) printf ("%5d",array[i]); printf ("\n"); } void sort(a,n) int a [ ],n; { int i,j, t; for (j=0;j<n-1;j++) for (i=0;i<n-j-1;i++) if (a[i]>a[i+1]) { t=a[i]; a[i]=a[i+1]; a[i+1]=t; } } array a
11 13 10 87 43 41 79 77 76 51 53 63 33 36 47 例 6.产生15个[10,90]上的数放入a数组中,找出其中 的素数放入b数组,并求b数组中元素的和 。 要求: 1. 求素数用函数sushu( )完成 2. 求素数的和用函数sum( )完成 a b 11 13 43 41 79 53 47 k=0 1 2 3 4 5 6 7
方法一: #include "stdlib.h" main() {int a[15],b[15]; int i,m=0; for(i=0;i<15;i++) { a[i]=random(81)+10; if(sushu(a[i])==1) {b[m]=a[i]; m++;} } printf("the array A is:\n"); for(i=0;i<15;i++) printf("%5d",a[i]); printf("\n"); printf("the array B is:\n"); for(i=0;i<m;i++) printf("%5d",b[i]); printf("\n"); printf("\nthe sum of array B is:%d\n",sum(b,m)); }
sushu(int k) {int n,x; x=1; if(k==1)x=0; for(n=2;n<k/2;n++) if(k%n==0) x=0; return(x); } int sum(b,n) int b[ ],n; {int i,s=0; for(i=0;i<n;i++) s=s+b[i]; return(s); }
方法二: #include ”time.h" #include "stdlib.h" main() {int a[15],b[15],i,m; randomize(); for(i=0;i<15;i++) a[i]=random(81)+10; m=sushu(a,b); for(i=0;i<m;i++) printf("%4d",b[i]); printf("\n"); printf("sum=%d\n", sum(b,m)); }
int sushu(a,b) int a[ ],b[ ]; { int i,j,k=0; for(i=0;i<15;i++) {for(j=2;j<=a[i]-1;j++) if(a[i]%j==0) break; if(j>a[i]-1) {b[k]=a[i];k++;} } return(k); } int sum(b,n) int b[ ],n; {int i,s=0; for(i=0;i<n;i++) s=s+b[i]; return(s); }
3、用多维数组作函数参数 1. 用多维数组元素作函数实参,这点与前述相同。 2. 用多维数组名作函数实参和形参,在被调用函数中对形参数组定义时可以指定每一维的大小, 也可以省略第一维的大小说明。 如:int a[3][10]; int a[][10]; 二者都合法完全等价。但是不能把第二维以及其它高维的大小说明省略。
例8.有一个3×4的矩阵,求其中的最大元素 。 main( ) { static int a[3][4]={{1,3,5,7},{2,4,6,8},{15,17,34,12}}; printf ("max=%d\n",max_value(a)); } max_value(array) int array[12]; { int i,max; max=array[0]; for(i=0;i<12;i++) if(array[i]>max) max=array[i]; return(max); } max_value(array) int array[ ][4]; { int i,j,k,max; max=array[0][0]; for (i=0;i<3;i++) for (j=0;j<4;j++) if (array[i][j]>max) max=array[i][j]; return(max); }
例9: 求 3×3 矩阵转置 23 34 7 23 34 7 2 56 17 21 4 36 2 56 17 21 4 36 交换a[i][j]与a[j][i]的值
void turn(array) int array[][3]; { int i,j,k; for (i=0;i<3;i++) for (j=0;j<i;j++) { k=array[i][j]; array[i][j]=array[j][i]; array[j][i]=k; } } main() { static int a[3][3]={{1,3,5}, {2,4,6},{15,17,34}}; int i,j; turn(a); for (i=0;i<3;i++) { for (j=0;j<3;j++) printf ("%5d",a[i][j]); printf ("\n"); } }