第四章 模块化程序设计

上传人:伴*** 文档编号:243042342 上传时间:2024-09-14 格式:PPT 页数:25 大小:92.50KB
返回 下载 相关 举报
第四章 模块化程序设计_第1页
第1页 / 共25页
第四章 模块化程序设计_第2页
第2页 / 共25页
第四章 模块化程序设计_第3页
第3页 / 共25页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第四章 模块化程序设计,前面各几章的学习,大家已有了编制小程序的经验。如果想编制大程序,在,C,语言下就得用模块化程序设计,其基本思想是将一个大的程序按功能分割成一些模块,使每一个模块都成为功能单一、结构清晰、接口简单、容易理解的小程序。,C,语言提供了支持模块化软件开发的功能:,1 函数式的程序结构。程序由一个或多个函数组成,每个函数都有各自独立的功能和界面。,2 允许通过使用不同的存储类别的变量,控制模块内部和外部的信息交换。,3具有预编译处理功能,为程序的调试、移植提供方便,支持模块化程序设计。,本章介绍这些功能及进行程序开发的基本方法。,4.1,函数,4.2,变量的存储属性,4.3,编译预处理,结束放映,4.1 函数,4.1.1,C,程序的结构,4.1.2,函数定义和函数声明,4.1.3,函数的传值调用,4.1.4,函数嵌套调用,4.1.5,函数的递归调用,C,程序结构(一),无论涉及的问题是复杂还是简单,规模是大还是小,用,C,语言设计程序,任务只有一种,就是编写函数,至少要编写一个主函数,main(),C,程序的执行就是执行相应的,main(),函数。即从它的,main(),函数的第一个花括号开始,依次执行后面的语句,直到最后的花括号为止。其它函数只有在执行了,main(),函数的过程中被调用时才执行。如图所示某一复杂程序执行的情况,:,main(),f1( );,f2( );,f1( ),f11();,.,f11(),f21(),f2( ),f21( );,f22(),f22(),.,程序执行过程中:主函数中含有调用函数,f1,f2,当执行到,f1( ),时函数,f1,才被调用,到达时,f2(),时函数,f2,才被调用。调用,f1,时,main(),向,f1,传递一些信息,并将流程转向,f1。,函数,f1,执行完后,向,main(),传回一些信息,再将流程返回,main()。,调用,f2,时的情形相同。当然在在执行,f1,函数时,也可以调用别的函数。,C,程序结构(二),高级语言中“函数”的概念和数学中“函数”的概念不完全相同。英语单词,function,有“函数”和“功能”两种介绍,高级语言中的函数实际上是功能的意思。当要完成某一个功能时,就用一个函数去实现它。在程序设计时首先要考虑,main(),函数中的算法,当,main(),中需要使用某一功能时,就用一个具有该功能的函数表达式表示。这时的函数,我们只知道它具有什么功能,其它先不作处理。设计完,main(),的算法并检验无误后,这时开始考虑它所调用的函数。如果在库函数中能找到,就可直接使用,否则再动手设计这些函数。这种设计方法称为自顶向下、逐步细化的程序设计方法。这种方法设计出来的程序在功率高,程序层次分明、结构清晰。复杂程序的层次可从以下图形中看出:,main(),f1(),f2(),f11(),f21(),f22(),C,程序结构(三),许多大型软件系统包含了相当丰富的,可供从事某一领域工作人员选用,如一个高等学校的信息管理系统就包含了教务、科研、人事、财务,设备、图书、后勤、办公室等子系统。每一个子系统以可分为许多子子系统。,这种软件为了方便用户大都采用菜单(,menu),方式,这种形式的软件,大家都用过。用户只需按一些简单的键,就能调用该功能,就像在饭店点菜一样那么方便。高等院校事务管理系统的模块结构如下:(程序,menu.c,),函数的定义与函数声明(一),函数就是在程序中设定的一个函数模块。一个函数是由变量声明部分与可执行语句组的成独立实体,用来完成一指定功能。除了系统提供的函数外,用户编制函数才是一种正确的选择。,(一).函数定义:,(函数类型、函数名、形参、函数体内容),函数返回值的类型说明,函数名,(,类型名 形式参数1,类型名 形式参数2,), 函数首部,说明部分 函数体,语句部分,函数类型:函数计算后的值是什么类型。,函数名: 用户命名的标识符,在主函数中调用的名字。,形式参数:函数中处理的变量,通过它接收主函数传过来的具体值。,函数体: 函数计算时的具体方法和函数的表达式。由变量定义部分和,语句组成。,函数的返回:由函数返回调用它的函数,可由以下返回形式:,return,表达式;,return;,可没有,return,语句,也可有多个,return,语句。,函数的定义与函数声明(二),函数名 (,类型名 形式参数1,类型名 形式参数2,),省略类型说明,,C,语言默认返回值为,int,型。,例:求两个双精度数这和的函数。,double add(double a,double b), double s;,s=a+b;,return s;,函数返回值的类型可以是整型、实型、字符型,和指针类型。以上函数的返回值是,double,型。,可用,double add(a,b) double a,b,来写函数首部。,定义函数可以没有参数,但一对括号不省略,如:,dummy() ,,函数体也可是空的,这样的函数什么也不做。编程时可作为一个虚设的部分。,函数举例:,编一个求两个数中最小数的函数,用循环语句多次调用该函数,找出十个数中的最小数。,(,ec711.c,),函数名,函数返回值类型,类型名与形式参数,函数返回值,函数声明(三),在,C,语言中,除了主函数外,对于用定义的函数要遵循“先定义,后使用”的规则。凡是未在调用前定义函数,,C,编译程序都 默认函数的返回值为,int,类型。对于返回值为其它类型的函数,若把函的定义放在调用之后,应该在调用之前对函进行说明。即只有函数的首部,一般形式为:,类型名 函数名(参数类型1,参数类型2,),如:,double add(double,double),或,类型名 函数名(参数类型1 参数名1,参数类型2,参数名2,),如:,double add(double p,double q),这里的参数是虚设的,实际上参数名常常省略。函数说明语句中的类型名必须与函数返回值的类型一致。,函数说明既可以作为一条单独的语句如:,double add(double,double),也可以与普通变量的说明在一起如:,double x,y,add(double,double),函数说明的位置与调用的关系,当在所有函数的外部、被调用之前说明函数时,在说明之后的任何位置都 可调用。,函数说明也可放在调用函数内的说明部分,但只能在该函内调用。,函数的传值调用(一),参数是函数调用时进行信息交换的载体,实参和形参结合,完成信息交换,函数的执行部分对这些传递来的数据进行处理后,返回相应的函数值。与数学中的知道函数表达式求函数值相类似。(,f(x)=3x+1;f(5)=?,f(0)=?),只不过是,C,语言中的函数自变量个数不只是一个。,1.当所调用的函数用于求出某个值时,函数的调用可作为表达式出现在允许表达式出现的任何地方,如:,y=add(3.0,4.0);,也可出现有关系表达式中用于条件判断。,2.如果只为了某些操作不返回函数值时,函数作为一条独立的语句,如: 函数名(实在参数);,函数调用时的语法要求:,1.调用函数时,函数名必须与定义的函数名字完全一致。,2.实在参数的个数必须与形式参数的个数一样。实在参数可以是表达式,类型上应按位置与形式参数一一对应匹配。如果类型不一致,编译系统会根据赋值兼容规定进行转换,若类型不赋值兼容,不给出错信息,程序继续执行,得不到正确的结果。,函数的传值调用(二),在,C,语言中,调用函数与被调用函数之间的数据可通过三种方法进行传递:,1.实在参数和形式参数之间进行数据传递。,2.通过,return,语句把函数值返回调用函数。,3.通过全局变量。这种方法不好。,在,C,语言中,数据只能从实参传递给形参,称为“按值”传递。也就是说,当用简单变量作为实在参数,用不能在函数中改变对应的值。观察参数传递两个实例:,函数参数之间的单向传递。(,ec71.c,),调用函数交换两个变量中的值。(,ec72.c,),没有返回值的调用:(,ec710.c,),函数的嵌套调用,C,程序的,main(),函数在调用一个函数时,被调用的函数,又要调用另一个函数,这种调用称为函数的嵌套调用。,例:把一个偶数分解为两个素数之和。,两次调用判断一个数是否为素数的函数; (,ec74.c,),(,ec75.c,),函数的递归调用,C,语言中的函数可以递归调用,即:可直接叵间接地调用自己。前者称为简单递归,后者称为间接递归,只讨论简单递归。,递归符合的三个条件:,1. 可以反要解决的问题转化为一个新的问题,而这个新的问题的解法仍与原野来的解法相同,只是所处理的对象有规律地递增或递减。,2 .可以应用这个转化过程使问题得到解决。,3 .必有一个明确的结束递归的条件。,例:用递归的方法求,n!。,把计算,n,的阶乘转化为,n-1,的阶乘,而计算方法相同。当计算到,n,为0时,问题完成。,函数的递归调用,函数递归调用如何分析执行结果:,fac,(5),fac,(5)=5*,fac,(4)=5*4*3*2*1=120,5*,fac,(4),fac,(4)=4*f(3)=4*3*2*1=24,4*,fac,(3),fac,(3)=3*,fac,(2)=3*2*1=6,3*,fac,(2),fac,(2)=2*,fac,(1)=2*1=2,2*,fac,(1),fac,(1)=1*,fac,(0)=1*1=1,1*,fac,(0),fac,(0)=1,fac,(,int,n) main(),int,t; ,int,m,y;,if(n= =1|n= =0) return 1;,scanf,(“%d”,else t=n*,fac,(n-1); return t; if (m0),printf,(“Input data error”);, else y=,fac,(m);,printf,(“%d”,y);,程序执行结果,ec1102.c,函数的递归调用,分析11.7程序的执行结果:,fun(6,&x) fun(6,&x)=fun(5,&x)+fun(4,&x) =5+3=8,fun(5,&x) fun(5,&x)=fun(4,&x)+fun(3,&x) =3+2=5,fun(4,&x) fun(4,&x)=fun(3,&x)+fun(2,&x) =2+1=3,fun(3,&x) fun(3,&x)=fun(2,&x)+fun(1,&x) =1+1=2,fun(2,&x) fun(2,&x)=1,fun(1,&x) fun(1,&x) =1,先下来,再返上去,这就是递归的分析的方法。,看程序执行结果,ec1103.c,程序举例,1.编写函数判断自变量是不为素数,若是素数,函数返回1,否则返回0。,(,ec73.c,),2.,编写函数,验证任意偶数可分解为两个素数之和,并输出这个素数。,(,ec74.c,),3.,(,ec75.c,),4.,用梯形法求函数的定积分。近似,公式,如下:,(,ec76.c,),5.,把小写字母转换成大写字母的函数。,(,ec77.c,),6.,统计输入字符的个数。,(,ec78.c,),7.,统计输入一段文本中的单词个数。用空格、换行符、跳格隔开。,(,ec79.c,),变量的存储属性,变量是对程序中数据的存储空间的抽象。前面介绍的数据类型是变量的操作属性。除此之外,影响变量使用的还有变量的存储属性。,变量的存储类型:计算机中的存储器分为内存和外存,除此这外不有一个称为寄存器的临时存储器,用来存储一些反复被加工的数据,存取速度比内存和外存要快得多。, 变量的生存期:,C,语言中的变量可用两种方法建立:在编译时分配存储单元,程序开始执行变量被创建,结束被撤销。这种变量生存期为程序执行的整个过程,在该过程中占有固定存储空间,称为永久存储;另一种是在某一段时间内存在,函数的形参和在函数体中的定义的变量,在程序进入该函数,才分配存储空间,函数结束,存储空间又被撤销,称为动态存储。,变量的可用域:分为两种:局部可用和全局可用,即局部变量与全局变量。,用存储属性可表示这三个方面的属性;分为四种存储类别说明,auto(,自动);,register(,寄存器);,static(,静态)和,extern(,外部)。以上属性说明,放在类型说明符的左边,也可以放在类型说明符的右边。,auto,int,k,l ;,int,auto k,l;,4.2.1,动态变量,4.2.2,静态变量,4.2.3,外部变量,动态变量(一),(一)自动(,auto),变量:,在变量定义时使用,auto,和不使用,auto,定义都是自动变量,这类变量的使用和前面所用变量一样。在主函数和子函数中变量名一样的变量分析程序时要特别注意。,1.自动变量是局部变量,自动变量只有在它定义的那个局部才能使用。,(,ec72.c),(ec712.c),2.,在对自动变量赋值之前,它值是不确定。,在编制累加和累乘的程序时,为什么要给和单元及积单元赋初值,原理就在这里。,(,ec713.c),程序计算的结果不确定。,(,ec714.c),变量,x,没有赋初值,执行的结果不可预测。,动态变量(二),二寄存器(,register),变量:,它的值保留的,CPU,的寄存器中,不占用内存单元,存取时间快,用它可提高程序的运行速度。通常把使用频率较高的变量定义为寄存器变量。定义与自动变量一样。,由于现在的计算机运算速度快,定义寄存器变量,很难分辨出它执行的情况。,打印乘法九九表的程序:,(,ec715.c),由循环控制变量,i,j,经常用,所以定义为寄存器变量。,由于各种计算机系统中的寄存器数目不同,寄存器的长度也不同,因此程序中定义寄存器变量的数量受限制。,静态变量,静态,static,变量:,它中的值和其它类型变量不一样在于:,1.在整个程序运行期间,静态局部变量在内存中占有永久性的存储单元,即使退出函数以后,再进入函数时,静态局部变量仍使用原来的存储单元。由于不释放原来的值,它的值可以使用到程序结束。,2.它的初值是在编译时赋予的,在执行时不再赋初值,末赋初值时系统自动赋初值0。,在函数多次被调用过程中静态局部变量的值具有可继承性。,(,ec716.c),(ec716a.c),静态局部变量的值只能在本函数中使用。,外部变量,一、外部变量(,extern),是全局,变量,定义在所有函数之外的变量称为外部变量。,(,ec717.c),(ec717a.c),(ec718.c),二、外部变量使用的几种情况,产生随机数,(,ec719.c),在不同的编译单位内用,extern,说明符来扩展全局变量的作用域 同一编译单位是在同一,C,的源程序中。不同的编译单位是在两个以上不同的,C,源程序内。通过头文件来进行互相访问的。,三、外部变量的副作用,主函数和子函数用同名外部变量产生的错误。,(,ec720.c),编译预处理,“编译预处理”就是在,C,编译程序对,C,源程序进行编译前,由编译预处理程序对这些编译预处理命令处理的过程。,C,语言的预处理均以 #,include #define,开头不加分号。,编译预处理是,C,语言的一个重要特点,它能改善程序设计环境,有助于编写易移植、易处理的程序,也是模块化程序设计的一个重要工具。,4.3.1,宏替换,4.3.2,文件包含,编译预处理(一),宏替换是用预处理命令 #,define,指定的预处理。,一、 不带参数的宏:,#,define,宏名 替换文本 #,define SIZE 1000,这种使用在前面的程序中已用到,如果替换文本还用到已定义的宏时,分析时要注意。,替换文本中包含已定义过的宏:,#,define PI 3.14,#define ADDPI (PI+1),#define TWO_ADDPI (2*ADDPI),如果有表达式:,x=TWO_ADDPI/2,则替换后为:,x=(2*(3.14+1)/2,若写成“,PI+1”,和“2*,ADDPI”,不加括号,替换后为,x=2*3.14+1/2;,因为是编译预处理,不计算后再用,就是先替换再计算。,编译预处理(二),二、带参数的宏替换:,(,ec721.c),类似于函数,但要根据宏定义时的表达式,要先替换,再计算。,例:#,define MU(X,Y) (X)*(Y),a=MU(5,6),替换为,a=(5)*(6)=30,#define MU(X,Y) X*Y,a=MU(5,6) a=5*6=30,a=MU(2+3,6) a=2+3*6=20,分析以下程序执行的结果:,#,define SQR(X) X*X,main(),int,a=10,k=2,m=1; /*,没加括号,替换结果为*/,a/=SQR(k+m)/SQR(k+m); /* k+m*k+m/k+m*k+m */,printf,(“%dn”,a);,文件包含,文件包含:,在,C,语言程序开发时,可以用文件包含的方法使得按照一定功能编制的存在文件中的某类宏被当前文件调用,而不需再去编制。只需在头文件中包含这些文件即可。,所谓文件包含,是在一个文件中,去包含另一个文件的全部内容。在以前的程序编制时已用过。,#,include,文件名,或 #,include ,在预编译时,预编译程序将用指定文件中的内容来替换此命令。,包含的文件的扩展名不一定用“.,h” ,也可以是,C,源程序“.,c”。,(file1.c),#include ,stdio,.h,标准输入输出函数 #,include ,conio,.h,屏幕控制函数,#,include ,stdlib,.h,随机函数等 #,include math.h,数学函数,#,include ,ctype,.h,字符函数 #,include string.h,字符串函数,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 小学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!