首页 第7章 用函数实现模块化程序设计

第7章 用函数实现模块化程序设计

举报
开通vip

第7章 用函数实现模块化程序设计null第七章 函 数第七章 函 数函数定义的一般形式 函数参数和函数的值 函数的调用 函数的嵌套调用 函数的递归调用 数组作为函数参数 局部变量和全局变量 变量的存储类别 内部函数和外部函数概 述概 述 函数是C源程序的基本模块,通过对函数模块的调用实现特定的功能。 一个C程序可由一个主函数和若干函数构成,由主函数调用其他函数,其他函数也可以互相调用。 从用户使用的角度看,函数可分为库函数和用户定义函数。 库函数:由C系统提供,用户无须定义,也不必在程序中作类型说明,只需在程序前包含有该函数原型的...

第7章 用函数实现模块化程序设计
null第七章 函 数第七章 函 数函数定义的一般形式 函数参数和函数的值 函数的调用 函数的嵌套调用 函数的递归调用 数组作为函数参数 局部变量和全局变量 变量的存储类别 内部函数和外部函数概 述概 述 函数是C源程序的基本模块,通过对函数模块的调用实现特定的功能。 一个C程序可由一个主函数和若干函数构成,由主函数调用其他函数,其他函数也可以互相调用。 从用户使用的角度看,函数可分为库函数和用户定义函数。 库函数:由C系统提供,用户无须定义,也不必在程序中作类型说明,只需在程序前包含有该函数原型的头文件即可在程序中直接调用。如前面反复用到的printf、scanf、getchar、putchar、gets、puts、strcat等函数均属此类。 用户定义函数:由用户按需要写的函数。对于用户自定义函数,不仅要在程序中定义函数本身,而且在主调函数模块中还必须对该被调函数进行类型说明,然后才能使用。 null由于采用了函数模块式的结构,C语言易于实现结构化程序 设计 领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计 。使程序的层次结构清晰,便于程序的编写、阅读、调试。 #include int main() /*主函数*/ { int max(int x,int y); /*函数原型声明*/ int a,b,c; scanf(“%d,%d”,&a,&b); c=max(a,b); /*调用函数max*/ printf(“max=%d”,c); return 0; } int max(int x,int y) /*定义max函数*/ { int z; if (x>y) z=x; else z=y; return(z); /*将z的值返回*/ }用户定义函数-举例在C程序中,一个函数的定义可以放在任意位置,既可放在主函数main之前,也可放在main之后。null概 述从主调函数和被调函数之间数据传送的角度看又可分为无参函数和有参函数两种。 #include int main() { void printstar(); /*函数原型声明*/ void print_message(); /*函数原型声明*/ printstar(); /*函数调用*/ print_message(); /*函数调用*/ printstar(); /*函数调用*/ return 0; } void printstar() /*函数定义*/ { printf("* * * * * * * * * * * * * * * *\n"); } void print_message() /*函数定义*/ { printf(" How do you do!\n"); }null函数定义的一般形式 类型标识符 函数名( 形式参数表列 ) { 声明部分 语句 } 有参函数比无参函数多了一个内容,即形式参数表列。在形参表中给出的参数称为形式参数,它们可以是各种类型的变量,各参数之间用逗号间隔。在进行函数调用时,主调函数将赋予这些形式参数实际的值。形参既然是变量,必须在形参表中给出形参的类型说明。 例: int max(int x,int y,int z) { int t; t=x>y?x:y; t=z>t?z:t; return t; }null形式参数和实际参数 函数的参数分为形参和实参两种。 形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。 实参出现在主调函数中,进入被调函数后,实参变量也不能使用。形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。  #include int main() { int max(int x,int y); int a,b,c; scanf(“%d,%d”,&a,&b); c=max(a,b); printf(“max=%d”,c); return 0; } int max(int x,int y) { int z; if (x>y) z=x; else z=y; return(z); }null形式参数和实际参数 函数的形参和实参具有以下特点: 1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。 2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。 3.实参和形参在数量上,类型上,顺序上应严格一致,否则会发生“类型不匹配”的错误。 4.函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。 null例:用函数交换两个变量的值。 #include int main ( ) { void swap(int x,int y); int a, b; a=5; b=10; /* 说明两个变量并赋初值 */ printf ("before swap a=%d, b=%d\n", a, b); swap(a, b); /* 用变量a和b作为实际参数调用函数 */ printf ("after swap a=%d, b=%d\n", a, b); return 0; } void swap(int x,int y)/*借助临时变量交换两个形参变量的值*/ { int temp; temp=x; x=y; y=temp; printf("in swap x=%d, y=%d\n", x, y); }函数间参数传递输出: before swap a=5, b=10 in swap x=10, y=5 after swap a=5, b=10null函数的返回值 函数的值是指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值。 函数的值只能通过return语句返回主调函数。 return语句的一般形式为: return 表达式; 或者为: return (表达式); 该语句的功能是计算表达式的值,并返回给主调函数。在函数中允许有多个return语句,但每次调用只能有一个return 语句被执行,因此只能返回一个函数值。 例如,定义一个函数,用于求两个数中的大数,可写为: int max(int a, int b) { if (a>b) return a; else return b; }null函数的返回值 如函数值为整型,在函数定义时可以省去类型说明符int。 不返回函数值的函数,可以明确定义为“空类型”,类型说明符为“void”。一旦函数被定义为空类型后,就不能在主调函数中使用被调函数的函数值了。 例: void printstar( ) { printf(“********************”); } 如果在主调函数中写下述语句 n = printstar( ); 就是错误的。 而只能写成: printstar( ); 为了使程序有良好的可读性并减少出错,凡不要求返回值的函数都应定义为空类型。 null函数调用C语言中,函数调用的一般形式为: 函数名(实际参数表) 在C语言中,可以用以下几种方式调用函数: 1、函数语句 把函数调用作为一个语句,例如:printstar(); 这时不要求函数带回值,只要求函数完成一定的操作。 2、函数表达式 函数出现在一个表达式中,例如:c+2*max(a,b); 这时要求函数带回一个确定的值以参加表达式的运算。 3、函数参数 函数调用作为一个函数的参数,实质上也是函数表达式调用, 例如:m=max(a,max(b,c))null例:用函数fact计算m阶乘。 #include int main( ) { int m, n; int fact( int x ); scanf("%d", &m); n = fact( m ); printf("%d!=%d\n", m, n); return 0; } int fact ( int x ) { int y; for ( y=1; x>0; --x ) y*=x; return (y); }函数执行过程 main ( ) { n = fact ( m ); }fact ( x ) { return (y ); }调用返回函数举例null例:计算:C(m,n) = m!/(n!*(m-n)!) #include int main( ) { int cmn, m, n; int fact(int); //说明函数fact的类型 scanf ("%d%d", &m, &n); cmn=fact(m)/(fact(n)*fact(m-n)); //三次调用fact printf ("The combination is %d\n", cmn); return 0; } int fact( int x ) /*定义fact函数*/ { int y; for ( y=1; x>0; --x ) y*=x; return(y); }函数举例null函数举例例:编写一个求幂的函数power(m,n),用于计算整数m的n次幂,其中n是正整数。 #include int main() { int power(int,int); /*函数原型声明*/ int i; for(i=0;i<10;i++) printf(“%d %d %d\n”,i,power(2,i),power(-3,i)); return 0; } int power(int m,int n) /*函数定义*/ { int i,p=1; for(i=1;i<=n;++i) p=p*m; return p; }null在调用函数之前,要先对被调用函数作声明 “声明”与“定义” 的区别: “声明”就是说明函数返回值的类型。 “定义”是给出函数的程序体。 函数原型(声明)的一般形式 (1)函数类型 函数名(参数类型1,参数类型2,……); (2)函数类型 函数名(类型1 参数名1,类型2 参数名2……);这种形式的函数声明与函数定义的首部唯一区别:函数声明语句的( )之后必须有分号,而函数定义首部的( )之后没有分号。对被调用函数的声明和函数原型null函数的嵌套调用main函数 { …… …… 调用函数 A; …… }函数 A { …… …… 调用函数 B; …… }函数 B { …… …… …… }调用调用返回返回C语言的函数定义都是互相平行、独立的,即C语句不能嵌套定义函数,但可以嵌套调用函数,即在调用一个函数的过程中,又调用另一个函数。null例: 输入4个整数,找出其中最大的数。用函数的嵌套调用编程。#include int main() { int m4( int, int, int, int ); int a,b,c,d,max; printf("Please enter 4 interger numbers:"); scanf("%d %d %d %d ",&a,&b,&c,&d); max=m4(a,b,c,d); /* 调用m4函数 */ printf("max=%d \n",max); return 0; } int m4(int a,int b,int c,int d) /* m4函数的定义 */ { int m2( int, int ),m; m=m2(a,b); /* 调用m2函数 */ m=m2(m,c); /* 调用m2函数 */ m=m2(m,d); /* 调用m2函数 */ return(m); }int m2(int a, int b) { if(a>b) return a; else return b; }运行情况如下: Please enter 4 interger numbers:11 45 –54 0↙ max=45null 例:用递归方法求n! 。已知:n阶乘的递归定义为: n! = 1 当 n = 1 时 n! = n * (n-1)! 当 n > 1 时 int main ( ) { int fact(int n); int n, p; scanf("%d", &n); p = fact(n); printf ("%d!=%d\n", n, p); return 0; } int fact(int n) { int r; if ( n == 1 ) r = 1; else r = n * fact(n-1); /* 递归调用 */ return (r); }函数的递归调用在一个程序中,若存在函数自己调用自己的现象就是构成了递归。null例:求菲波那奇序列:1,1,2,3,5,8,13,21,…… 建立问题的递归定义: f(n)=1 当 n=1或n=2 时 f(n)=f(n-1)+f(n-2) 当 n>2 时 程序: #include int main( ) { int i,f(int); for(i=1;i<=20;i++) printf(“%d\t”,f(i)); return 0; } int f(int n) { if (n==1||n==2) return (1); /*结束条件*/ else return ( f(n-1) + f(n-2) ); }函数的递归调用nullvoid f1(int n) { printf("%d",n%10); if(n/10!=0) f1(n/10); } void f2(int n) { if(n/10!=0) f2(n/10); printf("%d",n%10); }函数的递归调用#include int main() { f1(123); printf("\n"); f2(123); printf("\n"); return 0; }null汉诺塔问题 据说在约19世纪末欧洲的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔,游戏的目的是将最左边A杆上的圆盘,借助于B杆,全部移到C杆上,条件是一次仅能移动一个盘,且不允许大盘放在小盘的上面。18,446,744,073,709,551,615次1844亿亿次。每次1微秒,需要60万年分析:对A杆上的全部N个圆盘从小到大顺序编号,最小的圆盘为1号,次之为2号,依次类推,则最下面最大的圆盘的编号为N。函数的递归调用null第一步,将问题简化。假设A杆上只有2个圆盘,即汉诺塔有2层,N=2。移动方法: 1. 将上面小片移到B杆上。 2. 将下面的大片由A杆移到C杆上。 3. 将B杆上的小片移到C杆上。A杆C杆B杆函数的递归调用nullA杆C杆B杆第二步,对于一个有 N(N>1)个圆盘的汉诺塔,将N个圆盘分为两部分:上面的 N-1 个圆盘和最下面的N号圆盘。将“上面的N-1个圆盘”看成一个整体。 第三步,为解决 N 个圆盘的汉诺塔,可按如下方式进行操作:① 将A杆上面的N-1个盘子,借助C杆,移到B杆上; ② 将A杆上剩下的第N号盘子移到C杆上; ③ 将B杆上的N-1个盘子,借助A杆,移到C杆上。函数的递归调用null void move(char x, char y) { printf(“%c%c\n”,x,y); } void hanoi(int n, char one, char two, char three) /*将n个盘从one杆借助two杆,移到three杆*/ { if(n==1) move(one,three); else { hanoi(n-1,one,three,two); move(one,three); hanoi(n-1,two,one,three);} } int main( ) { int m; printf(“input the number:”); scanf(“%d”,&m); printf(“The step is:”); hanoi(m,’A’,’B’,’C’); return 0; } 函数的递归调用null 例:将一个一维数组中的素数输出。 #include #include void main ( ) { int sushu(int n); int i, a[10]={11,22,67,35,89,17,43,48,99,76}; for( i=0;i<10;i++ ) if( sushu(a[i]) ) printf(“%d is a sushu!\n”, a[i]); } int sushu(int n) { int flag=1,i; for(i=2; i<=(int)sqrt(n);i++) if (n%i==0) { flag=0; break; } return (flag); }数组作函数参数——数组元素实现单向的值传递null例:求给定一维数组a中各元素的平均值。 int main ( ) { float average( float [ ],int ); float a[10] = { 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9}; printf ("The average array is %f\n", average(a,10) ); return 0; } float average(float x[ ],int n) /*n为a中元素的个数*/ { int i; float sum=0; for ( i=0; imax) max=array[i][j]; return(max); } int main( ) { int a[3][4]={{1,3,5,7},{2,4,6,8},{15,17,34,12}}; printf(“max value is%d\n”,max_value(a) ); return 0; }数组名作函数参数-多维数组null例:给定年月日,计算它是这一年的第几天。 void main( ) { int day_tab[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31}, {0,31,29,31,30,31,30,31,31,30,31,30,31}}; int y,m,d,days( int[ ][13],int,int,int) ; scanf ("%d%d%d", &y, &m, &d); printf("%d\n", days( day_tab, y, m, d) ); } int days( int day_tab[ ][13],int year,int month,int day ) { int i,j; i = ( year%4==0 && year%100!=0 ) || year%400==0 ; /* 判定为闰年还是平年,i=0为平年,i=1为闰年 */ for ( j=1; jy?x:y; return(z); } int main( ) { extern A,B; /*声明外部变量*/ printf(“%d”,max(A,B)); return 0; } int A=13,B=-8; /*定义外部变量*/外部变量的声明null2.在不同的文件中使用外部变量和函数 当外部变量的定义与使用在不同的文件中,若一个文件要使用在另一个文件中定义的外部变量,就必须在使用该外部变量之前,使用“extern”存储类型说明符进行变量“外部”说明。 extern仅仅是说明变量是“外部的”,以及它的类型,并不真正分配存储空间。在将若干个文件连接生成一个完整的可执行程序时,系统会将不同文件中使用的同一外部变量连在一起,使用同一个系统分配的存储单元。 当被调用的函数在另一个文件中时,在调用该函数时,无论被调用的函数是什么类型,都必须用extern说明符说明被调用函数是“外部函数”。外部变量的声明null例: 下列程序由两个文件组成,请分析运行结果。 /* 文件一 */ int x = 10; int y = 10; /* 定义外部变量x和y */ void add ( ) { y = 10+x; x *= 2; } void main ( ) { extern void sub( ); /* 说明sub是void型的外部函数 */ x += 5; add( ); sub( ); /* 分别调用函数 */ printf ("x=%d; y=%d\n", x, y); } /* 文件二 */ void sub ( ) /* 函数sub定义在另一个文件中 */ { extern int x; /* 说明在另一个文件中的外部变量x */ x -= 5; }外部变量的声明null int f(int a) { auto int b=0; static int c=3; b=b+1; c=c+1; return(a+b+c); } int main( ) { int a=2,i; for(i=0;i<3;i++) printf("%d",f(a)); return 0; }例:观察静态局部变量与自动变量的值。静态变量—静态局部变量、静态外部变量int fac(int n) { static int f=1; f=f*n; return(f); } int main( ) { int i; for(i=1;i<=5;i++) printf("%d!=%d\n",i,fac(i)); return 0; }null对静态局部变量的说明: 静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动态存储空间,函数调用结束后即释放。 静态局部变量在编译时赋初值,即只赋初值一次;而对自动变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。 如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值则它的值是一个不确定的值。 静态局部变量null内部函数和外部函数内部函数 如果一个函数只能被本文件中其他函数所调用,它称为内部函数 定义的一般形式: static 类型标识符 函数名(形参表) 外部函数 在定义函数时,如果在函数首部的最左端冠以关键字extern,则表示此函数是外部函数,可供其他文件调用 在需要调用此函数的文件中,用extern声明所用的函数是外部函数null例:有一个字符串,内有若干个字符,今输入一个字符,要求程序将字符串中该字符删去。用外部函数实现。 /*file1.c*/ int main( ) {extern void enter_string(char str[80]); extern void delete_string(char str[],char ch); extern void print_string(char str[]); char c; char str[80]; enter_string(str); scanf(“%c”,&c); delete_string(str,c); print_string(str); return 0; }/*file2.c*/ #include void enter_string(char str[80]) { gets(str); }/*file4.c*/ void print_string(char str[]) { printf(“%s”,str); }/*file3.c*/ void delete_string(char str[],char ch) { int i,j; for(i=j=0;str[i]!=‘\0’;i++) if(str[i]!=ch) str[j++]=str[i]; str[j]=‘\0’; }
本文档为【第7章 用函数实现模块化程序设计】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_596908
暂无简介~
格式:ppt
大小:616KB
软件:PowerPoint
页数:0
分类:工学
上传时间:2012-12-28
浏览量:15