资源预览内容
第1页 / 共32页
第2页 / 共32页
第3页 / 共32页
第4页 / 共32页
第5页 / 共32页
第6页 / 共32页
第7页 / 共32页
第8页 / 共32页
第9页 / 共32页
第10页 / 共32页
亲,该文档总共32页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第4章 模块化设计与应用,主要内容 模块化程序设计 函数定义 函数调用 函数声明 函数的传递参数 函数的返回值 预处理,模块化分,4.1 模块化程序设计方法,4.1.1模块化程序设计思想 将整个系统进行分解成若干功能独立的,能分别设计、编程和测试的模块。 特点: 程序员能单独地负责一个或几个模块的开发。 开发一个模块不需要知道系统其它模块的内部结构和编程细节。 模块之间的接口尽可能简明,模块应尽可能彼此隔离。 具有可修改性 具有易读性 具有易验证性 模块化分方法:自上向下,逐步分解,分而治之,4.1 模块化程序设计方法,4.1.2模块规划实例,例4-1 简单计算器问题描述:完成一个简单的计算器程序。要求能够完成如下的常用运算:加、减、乘、除、取余、倒数、以e为底的对数、以10为底的对数、开平方、指数运算、正弦、余弦、正切、二、八、十、十六进制之间的相互转换、位运算符运算、位段位运算、求pi()和阶乘。,1.模块分类 2.模块功能细化,六则运算 对数运算 ,以10为底的运算 以e为底的运算 ,4.1.2模块规划实例,4.1 模块化程序设计方法,例4-2 学生成绩档案管理 问题描述:完成一个综合的学生成绩档案管理系统。要求能够管理N个学生的3门功课(英语、高数和C语言)的成绩,需要实现以下功能:读入/存储学生信息、录入/修改/删除学生基本信息、录入/修改成绩、按学号/姓名查询、排序、浏览、统计每门课的优、良、中等、及格、不及格人数。,4.1 模块化程序设计方法,1.模块分类 2.模块功能细化,学生信息维护 学生成绩维护 ,学生信息录入、修改、查询等 ,学 生 成 绩 管 理,学 生 档 案 管 理,查 询,统 计,读 入 学 生 信 息,录 入 学 生 信 息,修 改 学 生 信 息,删 除 学 生 信 息,录 入 成 绩,修 改 成 绩,存 储 学 生 信 息,按 学 号 查 询,按 姓 名 查 询,浏 览,排 序,4.2 函数,库函数;自定义函数 4.2.1 函数的定义 一般形式:,函数类型 函数名(数据类型 参数1, 数据类型 参数2, ) 函数体 ,函数运行完毕后返回值的类型,无加void,函数的唯一标识符合标识符命名规则,参数表没有加 void,函数定义不允许嵌套,4.2 函数,(1) 在计算机中只能求出近似值 (2) 通过截取所给公式的前n项来实现所要求的精度。n的大小由截取的条件决定,此处定为取到某一项的绝对值小于10-6为止 (3) 正负号交替;分母依次相差为2;可以用循环结构实现求和运算,例4-3(a) 定义一个函数,实现用公式 求的值。,/* 定义一个函数 */ /* purpose: 定义一个函数,求Pi的近似值 author : gcy created: 2008/08/12 14:58:22 */ #include float SelPi(void) /求pi int nSign=1; float fNumber=1.0,fTerm=1,fPi=0; while(fabs(fTerm)1e-6) fPi=fPi+fTerm; fNumber=fNumber+2; nSign=-nSign; fTerm=nSign/fNumber; return(4*fPi); ,4.2 函数,4.2.2 函数的调用 1. 函数声明,函数类型 函数名(数据类型 参数名1, 数据类型 参数名2, );,在主调函数之前,需对被调函数进行声明,以下三种形式可以不用函数声明 (1) 当被调用函数的函数定义出现在主调函数之前时。 (2) 如果在所有函数定义之前,在函数外部(例如文件或程序开始处)预先对各个函数进行了声明,则在主调函数中可以省去对被调用函数的说明。 (3) 若被调用函数的函数类型为int型时。,4.2 函数,4.2.2 函数的调用 2. 函数调用,函数名(实参表列);,(1) 在主调函数中调用一个函数时,函数名后面括号中的参数(可以是一个表达式)称为“实际参数”(简称“实参”)。 (2) 实参必须在类型上按顺序与形参一一对应和匹配。如果类型不匹配,C编译程序将按赋值兼容的规则进行转换。 (3) 如果实参表中包括多个参数表达式,对实参的求值顺序随系统而异。有的系统按自左向右顺序求实参的值,有的系统则相反,这一点读者尤其要注意。 (4) 调用函数时,函数名称必须与具有该功能的自定义函数名称完全一致。,#include void main() float SelPi(void);/函数声明 printf(pi=%.5fn,SelPi(); ,4.2 函数,4.2.2 函数的调用 2. 函数调用,注意: 在C语言中,可以用以下几种方式调用函数: (1) 函数表达式。函数作为表达式的一项,出现在表达式中,以函数返回值参与表达式的运算。这种方式要求函数是有返回值的。读者可以尝试一下把此例中的函数调用方式改成此种方式。 (2) 函数语句。C语言中的函数可以只进行某些操作而不返回函数值,这时的函数调用可作为一条独立的语句。 (3) 函数实参。函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作为实参进行传送,因此要求该函数必须是有返回值的。此例中的函数调用就属于此种方式。,4.2 函数,4.2.2 函数的调用 3.函数的参数 在主调函数和被调用函数之间的数据传递是通过函数的参数进行的,实际上这也是数据共享的一种形式。实参变量对形参变量的数据传递是单向传递,(1) 从数学的角度来说,可以一直迭代下去。但用计算机求解则不可以,并且大多数情况下得到的都是近似值。 (2) 需要一个条件限制迭代次数,这里采用前后两次求出的的差的绝对值小于所给的精度10-6这一限制条件。 (3) 迭代公式是很容易用循环结构实现的。,(1) 可以证明这个迭代公式对于任意初值x00都是收敛的。大家不妨尝试一下,只需要具备数列收敛的相关知识即可。该公式来源于牛顿迭代法。具体推导过程,可以参考“数值分析”或“计算方法”的方面的书籍。 (2) 程序中定义了函数SelSquareRoot(float fRadicand),指定了一个浮点类型的形式参数fRadicand,此时的fRadicand并没有实际的意义;在语句printf(%f的平方根为:%fn,fRadic,SelSquareRoot(fRadic);当中,将实际的参数fRadic赋给了形参fRadicand,相当于fRadicand =fRadic,并且通过函数调用,开始执行函数SelSquareRoot ()。 (3) 由于主调函数main()放在被调用函数SelSquareRoot ()之后,所以这里可以不进行函数声明。,4.2.2 函数的调用 3.函数的参数,注意: (1) 在函数没有被调用时,函数中的形参只是一个符号,系统并不为之分配内存空间,只有该函数被调用时,才会为之分配存储空间,并且在调用结束后,形参所占的内存也被释放。 (2) 在内存中,实参单元与形参单元是不同的单元。 (3) 实参可以是常量、变量或表达式,但要求它们有确定的值,也就是说,在调用函数时必须给形参赋以确定的值。 (4) 在被定义的函数中,必须指定形参的类型,并且实参与形参的类型应一致,否则将发生类型“不匹配的错误”。 (5) 形参在获得值之后便与实参相脱离,此后无论形参发生了怎样的改变,都不会影响到实参。,例4-5 定义一个有两个参数函数Swap,函数Swap能够完成对这两个参数的值的交换。,由此可以看出,虽然在函数Swap()中,变量nNum1和nNum2的值已经交换,但并没有影响到主函数中的nNumber1和nNumber2的值,此时仍然输出为nNumber1=4,nNumber2=7。这里,请读者思考一下:有没有办法使最后的输出结果为nNumber1=7,nNumber2=4呢?请到后面的第6章中找答案。 对于主调函数和被调用函数之间的数据传递是通过函数参数实现的,实参变量对形参变量的数据传递是单向传递,即只由实参传给形参,而不能由形参传回来给实参的内容已讲述完毕。但读者可能希望通过函数调用使主调函数能得到一个被调用函数的执行结果,这又该如何实现呢?,return ( 返回表达式 );,4. 函数返回值 函数的返回值是通过函数中的return语句获得的。return语句将被调函数中的一个确定值带回主调函数中去。return语句的一般格式是:,注意: (1) return语句的功能:返回主调函数,并将“返回表达式”的值带给主调函数。 (2) 函数的返回值可以有一个以上的return语句,哪一个return语句起作用要看使用的具体环境。 (3)函数的返回值是确定的。这里包含两层意思,一是函数值的类型确定。二是函数的返回值确定,即在return语句中的表达式的值必须确定。 (4)调用函数中无return语句,并不是不返回一个值,而是一个不确定的值。为了明确表示不返回值,可以用“void”定义成“无(空)类型”。为了使程序具有良好的可读性并减少出错,凡不要求返回值的函数都应定义为空类型,而不使用系统的缺省处理。 (5)在定义函数时,对函数类型的说明,应与return语句中返回值表达式的类型一致。如果不一致,则以函数类型为准。系统将缺省函数类型按整型(int)来处理,5. 函数调用的执行过程,4.3预处理,预处理命令是由ANSI统一规定的,但不是C语言本身的组成部分,不能直接对它们进行编译。根据预处理命令对程序作相应的处理,使程序不再包括预处理命令,再由编译程序对预处理后的源程序进行通常的编译处理,得到可执行的目标代码。 C语言提供了多种预处理功能,合理地使用预处理功能编写的程序便于阅读、修改、 移植和调试,也有利于模块化程序设计。,4.1 模块化程序设计方法,4.3.1文件包含 所谓“文件包含”是指一个源文件将另外一个或多个源文件的全部内容包含到本文件之中。它是C预处理程序的一个重要功能,其一般形式为: #include 文件名 #include (1) 在文件头部的被包含的文件称为“头文件”或“标题文件”,常以“.h”为后缀(h为head的缩写)。 (2) 一个#include命令只能指定一个被包含文件, (3) 文件包含允许嵌套, (4) 文件包含命令的功能是把指定的文件插入该命令行位置取代该命令行,从而把指定的文件和当前的源程序文件连成一个源文件。,4.3.1文件包含,(5) 包含命令中的文件名可以用双引号括起来,也可以用尖括号括起来, (6) 如果文件1包含文件 2,而文件2中要用到文件3的内容,则可在文件1中用两个#include命令分别包含文件2和文件3,且文件3应出现在文件2之前,即在文件1中定义。 (7)如果需要修改一些常数,不必修改每个程序,只需修改一个文件(头部文件)即可。 (8)使用“文件包含”命令,还可以减少编程人员的重复劳动。 4.3.2宏定义 在C语言源程序中允许用一个标识符来表示一个字符串, 称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去替换, 这称为“宏替换”或“宏展开”。在C语言中,“宏”分为有参数和无参数两种。 1. 不带参数的宏定义 #define 标识符 字符串,(1) 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的替换,字符串中可以包含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。 (2) 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。 (3) 宏定义必须写在函数之外,其作用域为定义命令之后到本源程序结束。 (4) 源程序中若宏名在引号里,则预处理程序不对其作宏替换,而把宏名当作字符串处理。 (5) 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号