第3章 模块化程序设计_第1页
第3章 模块化程序设计_第2页
第3章 模块化程序设计_第3页
第3章 模块化程序设计_第4页
第3章 模块化程序设计_第5页
已阅读5页,还剩54页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第3章模块化程序设计

3.1模块化程序设计思想★

3.2函数定义★★★★

3.3函数调用★★★★

3.4函数的原型与声明★★★★

3.5函数的嵌套与递归★★

3.6库函数★

3.7变量的作用域与存储类型★★★★

3.8指针与函数★★★★3.1模块化程序设计思想模块化是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程。每个模块完成一个特定的子功能,所有的模块按某种方法组装起来,成为一个整体,完成整个系统所要求的功能。把整个程序划分为若干个功能单一、相对独立、较易求解的程序模块,然后分别予以实现,最后再把所有的程序模块整合起来,这种在程序设计中逐步分解、分而治之的策略,被称为模块化程序设计方法。C语言中用函数实现模块的功能。【例3.1】求表达式的值。其中,K、M、N是正整数。#include<stdio.h>voidmain(){ inti,k,m,n; doublefk,fm,fn; scanf("%d%d%d",&k,&m,&n);

fk=1; for(i=1;i<=k;i++) fk=fk*i;

fm=1; for(i=1;i<=m;i++) fm=fm*i;

fn=1; for(i=1;i<=n;i++) fn=fn*i; printf("%f\n",fk/(fm+fn));}该程序将所有代码都放在了main函数中,阶乘的实现代码重复了3次,而该功能可以独立出来,通过自定义一个函数实现,在main函数中调用3次即可得到阶乘结果。voidmain(){intk,m,n;doublefk,fm,fn;scanf("%d%d%d",&k,&m,&n);

fk=fact(k);fm=fact(m);fn=fact(n);

printf("%f\n",fk/(fm+fn)); }#include<stdio.h>doublefact(intn){

inti; doublef=1; for(i=1;i<=n;i++) f=f*i; returnf;}按照模块化程序设计思想分析,该程序可以划分成3个模块:①输入数据模块②计算阶乘模块③输出结果模块每个模块用一个函数实现,再在主函数main中直接调用这些函数即可实现整个程序。输入/输出模块系统提供了相应的函数实现,剩下的任务就是编写自定义函数实现计算阶乘的模块。3.2函数定义根据模块化程序设计的思想,一个较大的程序一般应分为若干个程序模块,每一个模块包含一个或多个函数,每个函数实现一个特定的功能。一个C语言程序由一个主函数和若干其他函数构成。程序的执行从主函数的入口开始,到主函数的出口结束,其间主函数可以调用其他函数,其他函数之间也可以相互调用。在C语言中,函数分为以下两种:(1)

库函数由系统提供,用户不用定义,只需用#include命令包含其头文件,即可直接使用。如:printf()、scanf()、sqrt()等。(2)自定义函数是用户根据具体需求编写的,以完成相应的功能。

函数定义就是编写实现函数功能的程序模块。和变量的先定义、后使用一样,函数在使用之前也必须先定义,然后才能调用。voidmain(){ intk,m,n; dlublefk,fm,fn; scanf("%d%d%d",&k,&m,&n);

fk=fact(k); fm=fact(m); fn=fact(n);

printf("%f\n",fk/(fm+fn)); }函数定义格式:

函数返回值类型函数名(形参表){函数体}#include<stdio.h>doublefact(intn){

inti; doublef=1; for(i=1;i<=n;i++) f=f*i; returnf;}例如:doublefact(intn){…}函数调用格式:函数名(实参表);例如:fk=fact(k);函数名:命名规则同变量相同;同一个文件中函数名不能重复!形参表:用于在主调函数和被调函数间传递数据。需说明参数的个数和类型,多个形参间用逗号间隔,也可以无形参。形参与实参一一对应。函数定义的说明形参书写格式:每一个参数都要写上数据类型和参数名;参数之间以逗号分隔,无参数时一般写上void或什么也不写。floataverage(floata1,floata2,floata3){……}形参不能写成:floata1,a2,a3

×函数定义的说明函数体:由左右花括号括起来的部分。包括说明部分和语句部分,是实现函数的核心部分。

说明部分:定义函数内除形参以外的其它变量等;

语句部分:实现函数功能的执行语句;类型标识符函数名(形参表){

说明部分;

语句部分;}类型标识符:当函数有返回值时,在函数名前指定函数返回值的类型。

若省略类型标识符,默认为int。

若函数无返回值,函数定义时应写上void。①C语言不允许在一个函数内定义另一个函数,即不能嵌套定义。所有函数在书写时都是平行的。main(){floata,b,s;scanf("%f%f",&a,&b);s=area(a,b);printf("s=%f",s);}floatarea(floata,floatb){floats;s=a*b;returns;}×嵌套定义注意注意当参数表中的参数个数多于1个时,它和普通变量的定义稍有区别。普通变量定义如下:inta;/*以分号结束*/intb;函数中的参数定义为:(inta,intb)/*以逗号分隔,最后不需要符号*/普通变量定义如下:inta,b;/*多个类型相同的变量可以一起定义*/函数中的参数定义为:(inta,intb)/*数据类型和参数必须成对出现,有一个参数就必须有一个数据类型*/例:①编写一个函数,打印一行信息“Howdoyoudo!”printf("Howdoyoudo!\n");____print(____){}void

voidmain(){}print();#include<stdio.h>经验1:数据已知或固定则不需要作为参数传递;值事先不确定则需要参数传递!经验2:不要求计算结果或没有计算出任何数值则不需要返回值。②求整数x的n次幂(n>0,且为整数)______

power(__________){}intx,intndoublefor(i=1;i<=n;i++)p=p*x;inti;doublep=1;return(p);voidmain(){}scanf("%d%d",&x,&n);s=power(x,n);printf("%d^%d=%lg\n",x,n,s);printf("Inputx,n:");intx,n;doubles;#include<stdio.h>主函数应包含哪些内容:voidmain(){}变量定义输入数据处理——函数调用输出结果③将指定的字符打印n次____print(_____________){}charch,intnvoidfor(i=1;i<=n;i++)putchar(ch);inti;printf("\n");voidmain(){}printf("Inputch(char):");scanf("%c",&ch);printf("Inputn(int):");scanf("%d",&n);print(ch,

n);charch;intn;#include<stdio.h>3.3函数调用3.3.1函数调用的形式1、形式:函数名(实参表列);2、说明①实参表列由0到多个实参名组成,实参之间用逗号分隔;②实参与形参的个数、类型和顺序要一致;③调用无参函数的格式为:函数名();#include<stdio.h>intmax(intx,inty){intz;if(x>y)z=x;elsez=y;return(z);}voidmain(){inta,b,c;scanf("%d%d",&a,&b);c=max(a,b);printf("max=%d\n",c);}3、函数调用的方式①函数调用语句:–无返回值函数的调用

由函数调用加上分号构成,在主调函数中可作为一个独立的语句;此时不要求函数带回返回值。printf("ThisisaCprogram");②函数表达式:

函数调用作为一个运算对象出现在表达式中,此时要求函数带回一个确定的值以参加表达式的运算。c=max(a,b);y=2*pow(x,2.5);③函数参数:

函数调用作为另一个函数的实参,其值作为一个实际参数传给被调函数的形参;此时也要求函数带回一个确定值。m=max(a,max(b,c));printf("%d\n",max(a,b));3.3.2函数间的参数传递定义函数的目的是为了实现某个特定功能。当函数被调用时,一般需要给它传递一些数据,供它直接处理或辅助它实现具体的功能。把需要参数的函数称为有参函数,不需要参数的函数称为无参函数。形式参数:定义函数时函数名后面括号内的变量,简称形参实际参数:调用函数时函数名后面括号内的变量,简称实参#include<stdio.h>intmax(intx,inty){return(x>y?x:y);}voidmain(){inta,b,c;scanf("%d%d",&a,&b);c=max(a,b);printf("Max=%d.\n",c);}形参实参定义函数时需要解决的问题:有没有参数:若有,则从主调函数中传递数据。参数的个数参数的类型:int、float、double、char或指针是否有返回值:若有,则向主调函数返回计算结果。返回值的类型编写函数的原则:数据的输入输出均在主调函数中进行,通过参数将要计算的数据传入被调函数,由被调函数进行计算,并通过返回值返回计算结果。【例3.2】输入两个整数,求其平均值。要求用函数实现平均值的计算。有没有参数:参数的个数:参数的类型:是否有返回值:返回值的类型:#include<stdio.h>doubleaverage(intx,inty){doubleresult;result=(x+y)/2.0;returnresult;}voidmain(){inta,b;

doubleave;scanf("%d%d",&a,&b);

ave=average(a,b);printf("ave=%.1f\n",ave);}有2int有float或double说明:①程序在编译时不为形参分配存储空间,只有当函数被调用时,形参才被分配存储空间,并在调用结束后释放所占的存储空间。②形参只能是变量;而实参可以是常量、变量、表达式或具有返回值的函数调用,但要求它们有确定的值。调用时将实参的值传递给形参。m=max(3,a+b);/*x=3;y=a+b;*/m=max(a,max(b,c));/*x=a;y=max(b,c);*/③C规定,实参对形参的数据传递是“值传递”,即单向传递。只能把实参的值传送给形参,而不能把形参的值反向传送给实参。④在内存中,实参与形参占用不同的内存单元,因此即使同名也互不影响。#include<stdio.h>voidsum(intx,inty,intz){x=10;y=20;z=x+y;printf("x=%d,y=%d,z=%d\n",x,y,z);}voidmain(){inta=1,b=2,c=3;sum(a,b,c);printf("a=%d,b=%d,c=%d\n",a,b,c);}x=10,y=20,z=30a=1,b=2,c=33.3.3函数的返回值intmax(intx,inty){intz;z=x>y?x:y;

return(z);}1.函数的返回值是指函数被调用之后,执行函数体中的程序段所取得的、并返回给主调函数的值。函数的返回值只能通过return语句返回到主调函数。return语句的一般形式是:return(表达式);或

return

表达式;2.函数返回值的类型:在定义函数时指定。intmax(intx,inty)doublepower(intx,inty)C语言规定,凡不指定类型的函数,自动按整型(int)处理。max(intx,inty)intmax(intx,inty)

return语句的作用是终止当前函数的执行并将一个确定的值带回主调函数中。

函数值的类型与return语句中表达式的类型应一致;若不一致,则以函数类型为准(自动转换)。intmax(doublex,doubley){return(x>y?x:y);}3.一个函数可以有多个return语句,但每个return后的表达式类型要相同;每次调用只能有一个return语句被执行,因此函数的返回值只能有一个;当执行到其中任何一个return语句时,会立即返回主调函数。4.对于有返回值的函数,若return语句后面没有表达式,或没有return语句,此时带回一个不确定的返回值。return;5.为了明确表示“不带回值”,可以用void定义“无类型”(或称“空类型”,即无返回值)。voidmain(){…}例:定义一个函数,判断整数m是否是素数。是素数返回整数1,不是返回0。isPrime(){

}intmintk=sqrt(m);for(i=2;i<=k;i++)if(m%i==0)break;if(i<=k)elsereturn(0);return(1);inti,k;intisPrime(intm){inti,k;k=sqrt(m);for(i=2;i<=k;i++)if(m%i==0)

return(0);

return(1);}3.4函数的原型与声明

在函数调用之前应当对所调用的函数进行声明,指出该函数的返回值的类型以及形参的个数和类型,编译器根据此信息对函数调用进行语法检查,保证参数及返回值的正确性。1.函数声明的格式:函数类型函数名(形参表);floatfun(doublea,intb,floatc){……}可以声明为以下几种形式:

floatfun(doublea,intb,floatc);floatfun(double,int,float);floatfun(doublex,inty,floatz);2.说明:①函数声明的位置:一种是在主调函数中对被调函数进行函数声明;另一种是在所有函数的外部进行函数声明(推荐)。②如果被调函数出现在主调函数之前,可以不必进行声明。#include<stdio.h>intmax(intx,inty);voidmain(){……}intmax(intx,inty){……}#include<stdio.h>intmax(intx,inty){……}voidmain(){……}3.5函数的嵌套与递归3.5.1函数的嵌套调用C语言的函数定义都是互相平行、独立的,即不允许嵌套定义函数(在一个函数内部定义另一个函数)。但是,可以嵌套调用函数。所谓嵌套调用是指在一个函数的定义中出现对另一个函数的调用,即在被调函数中又调用其他函数。voidmain(){:

fun();:}voidfun(void){:

g();:}main函数fun函数g函数调用调用嵌套调用例:计算2~n之间所有素数的和。voidmain(){输入n(n是整数)求和---s=sum(n)输出s}intsum(intn){for(i=2,s=0;i<=n;i++)if(i是素数)s+=i;return(s);}intisPrime(intm){inti,k;k=sqrt(m);for(i=2;i<=k;i++)if(m%i==0)return(0);return(1);}组织成一个完整的C程序:#include<stdio.h>#include<math.h>intisPrime(intm){inti,k;k=sqrt(m);for(i=2;i<=k;i++)if(m%i==0)return(0);return(1);}intsum(intn){inti,s=0;for(i=2;i<=n;i++)if(isPrime(i)==1)s+=i;return(s);}voidmain(){输入n(n是整数)求和---s=sum(n)输出s}voidmain(){intn,s;printf("Inputn(n>1):");scanf("%d",&n);

s=sum(n);printf("s=%d\n",s);}3.5.2函数的递归调用(不讲)函数在被调用的过程中,又直接或间接的调用自身,则称函数的递归调用。floatfunc(intn){intm;floatf;

……f=func(m);

……}(1)直接递归调用func1(intn){intm;

……

func2(y);

……

}func2(intx){inty;

……

func1(a);

……

}(2)间接递归调用例:输入一个非负整数n,利用递归计算n!f(n)=n*f(n-1)(n>0)1(n=0)分析:n!=n*(n-1)!即longintfact(intn){longintf;if(n==0)

f=1;else

f=n*fact(n-1);return(f);}main(){intn;longintresult;

longintfact();while(1){printf("Inputadata:");scanf("%d",&n);if(n>=0)break;}result=fact(n);printf("result=%ld",result);}保证输入非负整数n=5result=fact(5)=5*fact(4)=4*fact(3)=3*fact(2)=2*fact(1)=1*fact(0)=1result=120递推回溯递归过程图示用递归求解问题的特点存在递归的终止条件存在能使问题求解的递归方式使用递归的优缺点优点:程序简洁,代码紧凑。缺点:每调用函数一次,在内存堆栈区分配空间,用于存放函数变量、返回值等信息,所以递归次数过多,可能引起堆栈溢出,且时间效率较差。例:求n的阶乘#include<stdio.h>/*非递归的方式*/floatfac(intn){floatf;inti;f=1;for(i=1;i<=n;i++) f=f*i;return(f);}voidmain(){intn;floaty;printf("Inputaintegernumber:");scanf("%d",&n);

y=fac(n);printf("%d!=%.0f",n,y);}#include<stdio.h>/*递归方式*/#inlcude<stdlib.h>floatfac(intn){floatf;if(n<0)exit(0);elseif(n==0||n==1)f=1;elsef=fac(n-1)*n;return(f);}voidmain(){floaty;intn;printf("Inputaintegernumber:");scanf("%d",&n);

y=fac(n);printf("%d!=%.0f",n,y);}递归的终止条件递归方式main函数输入m3y=fac(m)输出y6调用facmn3因3!=1或0f=3*fac(3-1)返回f=6调用facmn2返回f=2返回f=1因2!=1或0f=2*fac(2-1)调用facmn1因1==1f=1结束上例递归调用过程:3.6库函数库函数:即系统已经定义好、具有特定功能的函数。这些函数可以直接使用,不必重新定义,但使用时需要用#include命令把相应的头文件包含进来。输入输出函数(头文件:stdio.h):printf()scanf()getchar()putchar()数学函数(头文件:math.h):sqrt()pow()exp()log10()fabs()字符串函数(头文件:string.h):strcpy()strcat()strcmp()strlen()各函数的功能见附录,使用时注意参数的个数和类型以及函数的返回值类型。3.7变量的作用域与存储类型3.7.1变量的作用域

变量的作用域:指该变量有效的区域。变量定义的位置不同,其作用域也不同,作用域是从空间角度对变量特性的一个描述。按照作用域,C语言中的变量分为局部变量和全局变量。1.局部变量#include<stdio.h>intmax(intx,inty){intz;if(x>y)z=x;elsez=y;return(z);}voidmain(){inta,b,c;scanf("%d%d",&a,&b);c=max(a,b);printf("max=%d\n",c);}局部变量是指在一个函数或复合语句内部(位于一对花括号之间)定义的变量;其作用域是本函数或复合语句的内部。x、y、z的有效范围a、b、c的有效范围说明:①main函数中定义的变量是局部变量,只能在main函数中使用②不同函数中可以使用相同名字的变量,它们占用不同的内存单元,相互独立③形式参数也是局部变量④复合语句中定义的变量,其作用域只是本复合语句voidmain(){inta,b;……{intc;c=a+b;

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论