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

下载本文档

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

文档简介

模块化程序设计方法第1页,共99页,2023年,2月20日,星期五模块化程序设计方法人们在求解一个复杂问题时,通常采用的是逐步分解、分而治之的方法也就是把一个大问题分解成若干个比较容易求解的小问题,然后分别求解。设计一个复杂的应用程序时,往往也是把整个程序划分为若干功能较为单一的程序模块,然后分别予以实现称为模块化(结构化)程序设计方法第2页,共99页,2023年,2月20日,星期五模块化程序设计方法是自顶向下、逐步求精的程序设计方法程序由程序单元构成使用三种基本控制结构(顺序、选择、重复)构造程序单元第3页,共99页,2023年,2月20日,星期五函数是C语言的程序模块在C语言中,函数是程序的基本组成单位利用函数,可以实现程序的模块化,使程序设计简单和直观,提高程序的易读性和可维护性把程序中常用的一些计算或操作编成通用的函数,以供随时调用,大大减轻程序员的代码实现工作量。第4页,共99页,2023年,2月20日,星期五函数是C语言的重要的语法单位;是C语言程序的组成单元。第5页,共99页,2023年,2月20日,星期五划分函数的方法1程序中可能有重复出现的相同或相似的片段;从中抽取出共同的内容,定义为函数使一项功能只定义一次,多次使用缩短程序,提高程序的可读性和易修改性第6页,共99页,2023年,2月20日,星期五划分函数的方法2程序中具有逻辑独立性的片段即使这种片段只出现一次,也可以定义为函数,在原来需要这段程序的地方写函数使用。这种做法的主要作用是分解程序的复杂性,使之更容易理解和把握。第7页,共99页,2023年,2月20日,星期五函数分类在C语言中可从不同的角度对函数分类。1.从函数定义的角度看,函数可分为库函数和用户定义函数两种。库函数由C系统提供,只需包含有该函数定义的头文件即可在程序中直接调用。

printf、sqrt、strcat等函数。第8页,共99页,2023年,2月20日,星期五用户自定义函数:必须通过函数定义(或函数说明)才能被调用由程序员自己定义第9页,共99页,2023年,2月20日,星期五2.从功能角度看,又可把函数分为有返回值函数和无返回值函数两种。(1)有返回值函数此类函数被调用执行完后将向调用者返回一个执行结果,称为函数返回值。由用户定义的有返回值的函数,必须明确返回值的类型。第10页,共99页,2023年,2月20日,星期五(2)无返回值函数此类函数用于完成某项特定的处理任务,执行完成后没有计算的结果。用户在定义此类函数时需要指定它的返回类型为空类型---void。第11页,共99页,2023年,2月20日,星期五3.从主调函数和被调函数之间数据传送的角度看可分为无参函数和有参函数两种(1)无参函数函数不需要外部信息;可以返回或不返回函数值。第12页,共99页,2023年,2月20日,星期五(2)有参函数(带参函数)函数需要外部信息,通过参数形式传递信息可以返回或不返回函数值第13页,共99页,2023年,2月20日,星期五主函数每个C程序里必须有一个名为main的特殊函数,称为主函数。主函数规定了整个程序执行的起点(程序入口)程序执行从main函数开始执行,一旦它执行结束,整个程序就执行结束。程序不能调用主函数,它将在程序开始执行时被自动调用。第14页,共99页,2023年,2月20日,星期五除了主函数外,程序里的其他函数只有在被调用时才能进入执行状态。一个函数要在程序执行过程中起作用,要么它是被主函数直接调用的,要么是被另外一个被调用正在执行的函数所调用的。没有被调用的函数在程序执行中不会起任何作用。第15页,共99页,2023年,2月20日,星期五C不允许函数嵌套定义。一个函数中再定义一个函数是非法的函数与函数之间通过传递参数和返回值相联系。第16页,共99页,2023年,2月20日,星期五6.1函数定义和调用6.1.1函数定义一般形式:

(返回值)类型说明符函数名(形式参数表){

类型说明执行语句

}函数体函数原型\函数首部(头)第17页,共99页,2023年,2月20日,星期五函数原型类型说明符是指函数返回值的数据类型。函数名—给自定义的函数取的名字。形式参数表—函数被调用时,接收调用函数传递的实参数。函数体—说明语句、执行语句块。通过return语句返回函数计算结果。第18页,共99页,2023年,2月20日,星期五定义函数时必须指明返回值类型(缺省时,为int)如果函数没有返回值,函数返回类型应该为void第19页,共99页,2023年,2月20日,星期五1.无参函数的一般形式类型说明符函数名()

{类型说明执行语句

}第20页,共99页,2023年,2月20日,星期五无参函数

voidSay_Hello(){

printf("Hello,howdoyoudo.\n");

return;}第21页,共99页,2023年,2月20日,星期五无参函数voidshow-five-row-stars(){inti;for(i=1;i<=5;i++)printf(“%s\n”,“******”);

return;}第22页,共99页,2023年,2月20日,星期五2有参函数的一般形式类型说明符函数名(形式参数表){类型说明语句}以“,”隔开形参说明

type形参变量名第23页,共99页,2023年,2月20日,星期五有参函数voidshow-many-row-stars(intn){inti;for(i=1;i<=n;i++)printf(“%s\n”,“******”);

return;}第24页,共99页,2023年,2月20日,星期五有参函数intabs(inta){return((a>0)?a:-a);}第25页,共99页,2023年,2月20日,星期五有参函数

intarea_s(inta,intb){return(a*b);

}第26页,共99页,2023年,2月20日,星期五求两个数中较小的数intmin(inta,intb){if(a>b)returnb;

elsereturna;}第27页,共99页,2023年,2月20日,星期五对于用户自己定义的函数函数需要先定义,再调用。否则,需要对函数进行声明。第28页,共99页,2023年,2月20日,星期五函数声明

函数声明:函数原型;

返回类型函数名(形参表);

参数表省略变量名

intmin(inta,intb);

intmin(int,int);第29页,共99页,2023年,2月20日,星期五注意:如果使用库函数,必须在源文件前部用#include命令包含必要的头文件。对所有未能在使用前给出定义的函数,都应给出函数原型声明。把函数声明放在所有函数的定义之前(不要写在函数内部)第30页,共99页,2023年,2月20日,星期五6.1.2函数调用通过对函数的调用来执行对应的函数体

C语言中,函数调用的一般形式为:函数名(实际参数表)对无参函数调用时则无实参表实参可以是常数、变量及表达式各实参之间用逗号分隔。第31页,共99页,2023年,2月20日,星期五函数调用过程执行流程转向由函数名指定的被调用函数实参一一对应地传递给函数的形参执行函数定义中的函数体。执行结束,通过return语句将值返回到调用处执行流程返回调用处;执行后面的语句第32页,共99页,2023年,2月20日,星期五

函数B函数调用及返回函数Areturn…callBendA返回地址第33页,共99页,2023年,2月20日,星期五函数调用的几种情况(1)函数表达式函数调用作为表达式中的一个操作数,以函数返回值参与表达式的运算。这种方式要求函数是有返回值的。

z=min(x,y)*2;第34页,共99页,2023年,2月20日,星期五(2)函数语句函数调用加上分号即构成函数语句。这种方式要求函数没有返回值。

printf("%d",a);

show-five-row-stars();第35页,共99页,2023年,2月20日,星期五(3)函数实参函数作为另一个函数调用的实参。要求该函数必须是有返回值的

a=min(min(x,y),z);第36页,共99页,2023年,2月20日,星期五实参的求值顺序在函数调用中还应该注意的一个问题是求值顺序的问题。所谓求值顺序是指对实参表中各量是自左至右使用呢,还是自右至左使用。对此,各系统的规定不一定相同。第37页,共99页,2023年,2月20日,星期五函数返回值被调用之后,将执行函数体中的程序段,取得并返回给主调函数一个值,称这个值为函数返回值,函数计算结构只能通过return语句返回return语句的一般形式为:

return表达式;或return(表达式);第38页,共99页,2023年,2月20日,星期五return语句在函数中允许有多个return语句但每次调用只能有一个return语句被执行,因此只能返回一个函数值。第39页,共99页,2023年,2月20日,星期五参数匹配(2)函数值的类型和函数定义中函数的类型应保持一致。如果两者不一致,则以函数定义类型为准,自动进行类型转换。(3)不返回函数值的函数,可以明确定义为void。第40页,共99页,2023年,2月20日,星期五6.2函数参数传递主调函数和被调函数之间通过参数传递数据C语言参数传递方式为传值调用。函数的参数分为形参和实参两种。实参的值单向传递给函数的形参,作为形参的值实参形参值第41页,共99页,2023年,2月20日,星期五变量的作用域能够访问变量的程序范围—变量的作用域变量按作用域分为全局变量和局部变量全局变量:任何函数外定义的变量作用域为整个程序局部变量:函数内部定义的变量和形参作用域为:定义该变量的函数第42页,共99页,2023年,2月20日,星期五变量的作用域还可以在符合语句中定义变量作用域仅为该复合语句第43页,共99页,2023年,2月20日,星期五形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。第44页,共99页,2023年,2月20日,星期五函数的形参和实参的特点形参只有在被调用时才分配内存单元函数结束时,释放所分配的内存单元形参只有在函数内部有效。实参可以是常量、变量、表达式和函数调用函数调用时,实参必须具有确定的值第45页,共99页,2023年,2月20日,星期五函数的形参和实参的特点

实参和形参在数量上、类型上和顺序上应严格一致第46页,共99页,2023年,2月20日,星期五函数调用例子intcube(intx)/*自定义函数*/{intcb;cb=x*x*x;return(cb);}/*函数返回值*/voidmain(){inti,v;scanf(”%d”,&i);

v=cube(i);/*函数调用返回值赋给变量v*/printf(”cube=%d\n”,v);}第47页,共99页,2023年,2月20日,星期五两个电阻的串联值和并联值floatseries(float,float);floatparallel(float,float);voidmain(){floatr1,r2,se,pa;scanf(”%f%f”,&r1,&r2);se=series(r1,r2);/*函数调用*/pa=parallel(r1,r2);/*函数调用*/printf(“%f%f\n”,se,pa);}第48页,共99页,2023年,2月20日,星期五floatseries(floatrs1,floatrs2)/*自定义函数*/{floatrs;rs=rs1+rs2;return(rs);}floatparallel(floatrp1,floatrp2)/*自定义函数*/{floatrp;rp=(rp1*rp2)/(rp1+rp2);return(rp);}第49页,共99页,2023年,2月20日,星期五函数调用中发生的数据传送是单向的只能把实参的值传送给形参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。第50页,共99页,2023年,2月20日,星期五voidswap(intx,inty){inttemp=x;x=y;y=temp;}swap(a,b)第51页,共99页,2023年,2月20日,星期五如果函数需要对实参进行修改,则形参的类型应该为指针类型:指针做参数;实参的值应该为地址。参数传递传的是地址值通过修改形参指向的目标变量,达到修改实参数据的目的(间接访问方式)。第52页,共99页,2023年,2月20日,星期五voidswap(int*x,int*y){inttemp=*x;*x=*y;*y=temp;}swap(&a,&b)第53页,共99页,2023年,2月20日,星期五完整程序#include<stdio.h>voidswap(int*,int*);/*函数声明*/voidmain(){inta=3,b=8;printf(”a=%d,b=%d\n”,a,b);

swap(&a,&b);/*函数调用*/printf(”a=%d,b=%d\n”,a,b);}voidswap(int*x,int*y)/*函数定义,形参定义为指针*/{inttemp=*x;*x=*y;*y=temp;}第54页,共99页,2023年,2月20日,星期五6.3函数与数组数组可以作为函数的实参有两种形式:数组元素(下标变量)作为实参;数组名作为函数的实参第55页,共99页,2023年,2月20日,星期五6.3.1数组元素作函数实参数组元素作为实参与普通变量作为实参是完全相同的在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值传送第56页,共99页,2023年,2月20日,星期五6.3.2数组作为函数参数实参是数组名;形参是数组;用数组作函数参数时,则要求形参和实参都必须是类型相同的数组。形参数组和实参数组为同一数组,共同拥有一段内存空间。对形参数组的操作就是对实参数组的操作第57页,共99页,2023年,2月20日,星期五floataver(floata[5]){inti;floatav,s=a[0];for(i=1;i<5;i++)s=s+a[i];av=s/5;returnav;}voidmain(){floatsco[5],av;inti;for(i=0;i<5;i++)scanf("%f",&sco[i]);av=aver(sco);printf("%6.2f\n",av);}第58页,共99页,2023年,2月20日,星期五形参数组和实参数组的长度可以不相同,

voidnzp(inta[8]);…intb[5];nzp(b);第59页,共99页,2023年,2月20日,星期五形参也可以不指定数组的长度

voidnzp(inta[])或用一个变量来表示数组元素的个数。

voidnzp(inta[],intn)

形参数组由n值动态地表示数组的长度。

n的值由主调函数的实参进行传送。第60页,共99页,2023年,2月20日,星期五

多维数组也可以作为函数的参数。在函数定义时对形参数组可以指定每一维的长度,也可省去第一维的长度。

intfun(inta[3][10])或

intfun(inta[][10])第61页,共99页,2023年,2月20日,星期五指针作为形参实参是变量地址voidswap(int*x,int*y){inttemp=*x;*x=*y;*y=temp;}swap(&a,&b)第62页,共99页,2023年,2月20日,星期五指针作为形参,实参是数组名数组名就是数组的首地址实参向形参传送数组的地址值形参得到该地址后也指向同一数组第63页,共99页,2023年,2月20日,星期五求数组各项的累加和。#include<stdio.h>voidsum(int*array,intn);voidmain(){inta[10]={1,2,3,4,5,6,7,8,9,10};sum(a,6);}voidsum(int*array,intn){intsum=0;for(inti=0;i<n;i++){sum+=*array;array++;}printf(”%d\n”,sum);}第64页,共99页,2023年,2月20日,星期五6.4函数与指针返回指针的函数和指向函数的指针。第65页,共99页,2023年,2月20日,星期五6.4.1返回指针的函数函数的返回类型可以指针类型该函数返回的是地址返回指针的函数称为指针型函数第66页,共99页,2023年,2月20日,星期五类型说明符

*

函数名(形参表){…/*函数体*/}类型说明符表示了返回的指针值所指向的数据类型第67页,共99页,2023年,2月20日,星期五例在一个字符串中查找一个给定的字符若找到,则从该字符开始打印余下的字符,及该字符是字符串的第几个字符否则输出“nomatchfound”。第68页,共99页,2023年,2月20日,星期五#include<stdio.h>intcount;char*match(charc,char*sp);/*指针型函数*/voidmain(){chars[80],ch,*p;gets(s);ch=getchar();p=match(ch,s);/*函数调用,返回地址赋p指针*/if(p)printf(”%s%d\n”,p,(count+1));elseprintf(”nomatchfound”);}第69页,共99页,2023年,2月20日,星期五char*match(charc,char*sp){/*定义指针型函数*/count=0;while(c!=sp[count]&&sp[count]!=‘\0’)count++;if(!sp[count])return(0);return(&sp[count]);}/*返回子字符串的地址*/输入:programminga

输出:amming6第70页,共99页,2023年,2月20日,星期五6.5.2指向函数的指针(函数指针)略第71页,共99页,2023年,2月20日,星期五6.5函数与结构结构可以整体赋值可以将结构作为值参数传递给函数,也可以定义返回结构值的函数。1.将结构成员的值传递给函数--结构成员参数2.将整个结构作为参数值传递给函数,将这种参数称做结构参数。3.将结构的地址传给函数,也就是说传递指向结构的指针值,这称为结构指针参数。第72页,共99页,2023年,2月20日,星期五后两种方式把结构作为整体处理两种参数的作用方式和效果不同第73页,共99页,2023年,2月20日,星期五6.6.1结构指针在ANSIC标准中允许用结构变量作函数参数进行整体传送。但是这种传送要将全部成员逐个传送,特别是成员为数组时将会使传送的时间和空间开销很大,严重地降低了程序的效率。最好的办法就是使用指针做参数;实参传向形参的只是地址值,从而减少了时间和空间的开销。第74页,共99页,2023年,2月20日,星期五一组学生的平均成绩和不及格人数structstu{intnum;char*name;charsex;floatscore;}boy[5]={{101,"Liping",'M',45},{102,"Zhangping",'M',62.5}, {103,"Hefang",'F',92.5},{104,"Chengling",'F',87},{105,"Wangming",'M',58},};voidave(structstu*ps);第75页,共99页,2023年,2月20日,星期五voidmain(){ voidave(structstu*ps); ave(boy);}第76页,共99页,2023年,2月20日,星期五voidave(structstu*ps){intc=0,i;floatave,s=0; for(i=0;i<5;i++,ps++){s+=ps->score; if(ps->score<60)c+=1; }printf("s=%f\n",s);ave=s/5; printf("average=%f\nNopass%d\n",ave,c);}第77页,共99页,2023年,2月20日,星期五6.5.2结构型函数结构型函数:返回类型为结构类型的函数略第78页,共99页,2023年,2月20日,星期五6.6递归函数函数的递归调用是指调用一个函数的过程中直接或间接的调用该函数自身这种函数称为递归函数。C语言允许函数的递归调用。在递归调用中,主调函数又是被调函数,执行递归函数将反复调用其自身,每调用一次就进入新的一层。第79页,共99页,2023年,2月20日,星期五递归调用的过程分为:①递归过程:将原始问题不断转化为规模小了一级的新问题,从未知向已知推进,最终达到递归终结条件;②回溯过程:从已知条件出发,沿递归的逆过程,逐一求值返回,直至递归初始处,完成递归调用。第80页,共99页,2023年,2月20日,星期五例如:求n的阶乘

n!=n(n-1)!(当n>1时)n!=1(当n=0,1时)longfact(intn){if(n==1)return1;elsereturn(n*fact(n-1));}第81页,共99页,2023年,2月20日,星期五由于自调用过程在函数内必须设置某些条件,当条件成立时终止自调用过程,并使程序控制逐步从函数中返回。递归调用机制是栈数据结构实现的。函数之间由参数传递和返回值联系。第82页,共99页,2023年,2月20日,星期五n等于3递归调用过程如下;

fact(3)=3*fact(2)2*fact(1)1*fact(0)1

1*123*26第83页,共99页,2023年,2月20日,星期五图6-2递归调用示意图第84页,共99页,2023年,2月20日,星期五大多数递归函数都能用非递归函数代替例如:求两个整数a,b的最大公约数递归:longgcd1(inta,intb){if(a%b==0)returnb;returngcd1(b,a%b);}第85页,共99页,2023年,2月20日,星期五非递归longgcd2(inta,intb){inttemp;while(b!=0){temp=a%b;a=b;b=temp;}returna;}

使用递归函数简化了程序设计提高程序的可读性,但增加系统开销。第86页,共99页,2023年,2月20日,星期五6.7命令行参数main()函数也可以带有参数。从操作系统传递信息到main()中最常用的方法是使用命令行参数。使用命令行参数,可以使一个可执行程序的执行过程,像使用操作系统命令一样,在命令行中提供运行参数。第87页,共99页,2023年,2月20日,星期五使用命令行参数的形式为:voidmain(intargc,char*argv[]){……}argc参数个数,比实际参数个数多1;*argv[]字符型指针数组每个元素是指向参数(字符串常量)的指针

第88页,共99页,2023年,2月20日,星期五打印命令行参数。/*cla.c*/#include<stdio.h>main(intargc,char*argv[]){inticount=0;while(icount<argc){printf(“arg%d;%s\n”,icount,argv[icount]);icount++;}}第89页,共99页,2023年,2月20日,星期五编译、连接,生成可执行文件cla.exeC>cla.exedataelementstatement运行结果:arg0:claarg1:dataarg2:elementarg3:statement第90页,共99页,2023年,2月20日,星期五6.8标准库函数标准库函数是指由C

温馨提示

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

评论

0/150

提交评论