《模块化程序设计》PPT课件.ppt

上传人:xin****828 文档编号:15448217 上传时间:2020-08-10 格式:PPT 页数:76 大小:407.36KB
返回 下载 相关 举报
《模块化程序设计》PPT课件.ppt_第1页
第1页 / 共76页
《模块化程序设计》PPT课件.ppt_第2页
第2页 / 共76页
《模块化程序设计》PPT课件.ppt_第3页
第3页 / 共76页
点击查看更多>>
资源描述
1/76,第4章 模块化程序设计,2/76,主要内容,4.1 函数 4.2 变量的存储属性 4.3 模块的编译与链接 4.4 宏定义与宏替换,3/76,4.1.1 设计C语言程序就是设计函数,4/76,一个管理信息系统的结构,5/76,文本菜单实例,6/76,例4.1 显示菜单算法,7/76,#include 例4.1 一个显示菜单的主函数 #include void main(void) char choice; printf(t *大学信息管理系统*n); printf(t=n); printf(t 1.办公室管理 2.教务管理n); printf(t 3.科研管理 4.人事管理n); printf(t 5.财物管理 6.设备管理n); printf(t 7.图书资料管理 8.后勤管理n); printf(t 0.退出本系统n); printf(t-n); printf(t 请您在上述功能中选择(08):);,8/76,do choice=getche(); switch(choice) case 1:funt1(); break; case 2:funt2(); break; case 3:funt3(); break; case 4:funt4(); break; case 5:funt5(); break; case 6:funt6(); break; case 7:funt7(); break; case 8:funt8(); break; case 0:exit(0); break; default: printf(tInput error!n); break; while(1); ,9/76,4.1.2 函数结构,函数头 函数体 ,1. 函数头 函数类型 函数名(形参列表),2. 函数体 (1)声明语句 (2)可执行语句 (3)return语句 计算型函数,例sin(),返回一个计算结果 完成一项具体工作,返回完成结果 例printf函数,执行成功时,返回显示的字符数;失败时,返回一个负整数 只执行一个过程,不产生返回值:void函数,10/76,例4.2 求一个整数的绝对值,int absolutevalue(int x) return (x0?x:-x); ,11/76,例 4.3 输出n个空格的函数,void spc(int n) int i; for(i=0;in;i+) printf( ); return; ,12/76,例4.4,float y(float x) if (x0) return(x*x-x+1); else return(x*x*x+x+3); ,13/76,例4.5 (错误例),func(int n) if(n10) return(2*n+3); else return; ,14/76,3. 函数中变量的作用域,作用域是指一个程序段中的代码的作用范围。 一个函数中所定义的变量只在本函数中有效,在其他函数中不能使用这个变量。 即使在不同的函数中定义了同名变量,它们也是指不同的变量。,15/76,例4.6 (错误例),#include int func(int x) x=5; return x+3; int main(void) printf(x=%dn,x); return 0; ,16/76,4. 空函数,void null(void),17/76,4.1.3 函数定义与函数声明,函数定义:按照C语言的语法规则引入新的函数;函数不能嵌套定义。 函数声明:对所用到的函数的特征进行必要的说明,编译系统以函数声明所给出的信息为依据,对调用表达式进行检测。,18/76,函数定义和声明举例,函数定义 double func (double a, int b, char c) 函数声明可以是: double func (double a, int b, char c); double func (double, int, char); 以下为错误的声明: double func (a, b, c); func (double a, int b, char c);,19/76,函数的显式声明风格,void fun1(void); float fun2(float, int); int main(void) void fun1(void) x=fun2(a,b); float fun2(float x, int y) fun1(); ,20/76,4.1.4 虚实结合与传值调用,只有当执行函数调语句时,函数才被 执行: (1)将函数调语句中的实参的值传送给 函数形参。 (2)将流程从调用处转到被调用函数的 开头,开始执行函数体中的代码。,21/76,1. 函数调用时的虚实结合,#include float add(unsigned int , unsigned int); int main(void) float x=1.5, y=-5.7; printf(%f+%f=%fn,x,y,add(x,y); float add(unsigned int a, unsigned int b) printf(a=%u, b=%un,a,b); return a+b;,a=1, b=4294967291 1.500000+-5.700000=4294967292.000000,22/76,1. 函数调用时的虚实结合(错误例),#include float add(); int main(void) float x=1.5, y=-5.7; printf(%f+%f=%fn,x,y,add(x,y); float add(unsigned int a, unsigned int b) printf(a=%u, b=%un,a,b); return a+b;,a=0, b=1073217536 1.500000+-5.700000=1073217536.000000,23/76,2.传值调用的虚实结合过程,传值调用的特点: 形参与实参各占一个独立的存储空间 形参的存储空间是函数被调用时才分配的 函数返回时,形参存储空间被释放,24/76,例4.8 交换两个变量(错误例),void swap(int x,int y); void main(void) int a=3,b=5; swap(a,b); printf(a=%d,b=%dn,a,b); void swap(int x, int y) int temp; temp=x;x=y;y=temp; printf(x=%d,y=%dn,x,y); ,x=5, y=3 a=3, b=5,25/76,4.1.5 递归调用,在调用一个函数的过程中调用该函数本身,称为函数的递归调用。递归调用简称递归。 编写递归程序有两个要点: 一是要找到正确的递归算法,这是编写递归程序的基础; 二是要确定算法的递归结束条件,这是决定递归程序能否正常结束的关键。,26/76,例4.9 求n的阶乘,27/76,long rfact(int n); void main(void) printf(%ldn,rfact(0); printf(%ldn,rfact(3); printf(%ldn,rfact(5); printf(%ldn,rfact(-1); long rfact(int n) if(n0) printf(Negative argument!n); exit(-1); else if(n=1)return(1); else return(n*rfact(n-1); ,1 6 120 Negative argument,28/76,调用和回代过程,29/76,例4.10 汉诺塔(Hanoit)问题,相传在古代印度布拉玛庙里,几个和尚整天不停地移动着盘子。日复一日,年复一年,移盘不止。 移动盘子的规则:事先固定三根针,假设分别为A针、B针、C针,A针上套有64个中间带孔的盘子, 盘子大小不等,大的在下,小的在上要求把这64个盘子从A针移到C针, 在移动过程中可以借助于B针,每次只允许移动一个盘子,且移动过程中的 每一步都必须保证在三根针上都保持大盘在下、小盘在上。 据说当所有64个盘子全部移完的那一天就是世界的末日,故汉诺塔问题又被称为“世界末日问题”。,30/76,例4.10 汉诺塔(Hanoit)问题,不难计算, 对于n个盘子需要移动2n-1次 把64个盘子都移动完毕约需1.81019次假设每秒移动一次,约需一万亿年,若用现代电子计算机计算,设一微秒可计算(并不输出)一次移动,也几乎需要一百万年 目前,由于计算机运算速度的限制,我们仅能找出问题的解决方法并解决较小n值的汉诺塔。,31/76,汉诺塔问题算法,第一步,问题化简。设A针上只有一个盘子,即n1,则只需将1号盘从A针到B针。 第二步,问题分解。对于有n(n1)个盘子的汉诺塔,可分为三个步骤求解: 1. 将A针上n1个盘子借助于C针移到B针 2. 把A针上剩下的一个盘子移到C针 3. 将B针上n1个盘子借助于A针移到C针上述1、3两步具有与原问题相同的性质,只是在问题的规模上比原问题有所缩小 把第一步作为递归结束条件,将第二步分析得到的算法作为递归算法,可以写出如下完整的递归算法描述。,32/76,汉诺塔问题N-S图,33/76,汉诺塔代码,void movedisk(int n,char a,char b,char c) if(n=1) printf(%c - %cn,a,c); else movedisk(n-1,a,c,b); printf(%c - %cn,a,c); movedisk(n-1,b,a,c); ,34/76,汉诺塔代码,void main(void) int n; printf(Pleases input the number of diskes:); scanf(%d, ,35/76,运行结果,Pleases input the number of diskes: 3 The step moving 3 diskes is: A - C A - B C - B A - C B - A B - C A - C,36/76,程序分析,37/76,4.2变量的存储属性,变量是有类型的,数据类型是对变量运算属性的抽象,决定了该变量的取值范围和可施加的运算种类。除此之外,变量还有如下存储属性: (1) 一个变量在程序的哪个范围内是可以使用 的变量的可用域(或称可见性) (2) 变量何时生成以及何时被撤销变量的 生存期 (3) 它存储在哪种类型的存储器中以及采用何 种机制进行存储变量的存储区,38/76,1. 局部变量与全局变量,局部变量: 也称内部变量,是在函数(或块)内定义的,其作用域仅限于函数(或块)内。 全局变量:也称外部变量,是在函数外部定义的变量,它不属于任何一个函数。 全局变量属于一个源程序文件,其作用域是从定义点开始到整个源程序结束,39/76,例4.11 局部变量的作用域,void main(void) int a=3; printf(a1=%dn,a); int b=5; printf(a2=%d, b=%dn,a,b); printf(a3=%dn,a); ,a1=3 a2=3, b=5 a3=3,40/76,例4.12 局部变量的作用域,void main(void) int a=3; printf(a1=%dn,a); int a=5; printf(a2=%dn,a); ,a1=3 a2=5,41/76,课堂练习:局部变量的作用域,#include void f1(void),f2(int x); void main (void) int x=1; f1(); f2(x); printf(x=%dn,x); void f1(void) int x=3; printf(x=%dn,x+=3); void f2 (int x) printf(x=%dn,x+);,x=6 x=1 x=1,42/76,例4.13全局变量的作用域,void a(void) int a=1; printf(a1=%dn,a); int x=3; void b(void) printf(x1=%dn,x); void main(void) a(); b(); printf(x2=%dn,x); ,a1=1 x1=3 x2=3,43/76,4.14 全局变量与局部变量同名,#include int x=3; void main(void) int x=5; printf(x=%dn,x); ,x=5,当局部变量与全局变量同名时,局部变量会屏蔽全局变量,44/76,改写例4.8:交换两个变量,void swap(void); int a=3,b=5; void main(void) printf(a=%d,b=%dn,a,b); swap(); printf(a=%d,b=%dn,a,b); void swap() int temp; temp=a;a=b;b=temp; ,a=3,b=5 a=5,b=3,45/76,2.动态变量与静态变量,数据区分为自动存储区、静态存储区和动态分配区 自动存储区是按照栈结构组织的存储区,局部变量通常被存放在栈区,这些变量在进入所在的块时被创建,所在的块结束时被撤销。 静态存储区是在程序编译时就分配的存储区。其中中的变量在程序开始执行时被创建并自动初始化(数值变量被初始化为0),当程序结束时才被撤销。所以通常称静态变量的生存期是永久的。,46/76,4.2.2 C语言中变量的存储类型,C语言将可用域和生存期整合成4种存储类型。 (1)自动局部类型 在函数内部用标识符auto或register声明。 (2)静态局部类型 在函数内部用static声明。 (3)静态全局类型 在函数外部用static声明 (4)全局类型 在函数外直接声明,通称外部变量。,47/76,1 auto和register存储类型,对于局部变量和函数形参: auto 数据类型 变量名=初值表达式 register 数据类型 变量名=初值表达式 例如:,auto float a,b,c; register int i,j,k; func(register int a, register int b) ,48/76,2. 静态局部类型.,使用static修饰局部变量,即为静态局部类型 具有“永久生存期,局部可见性” 优点:既避免了全局变量的值被多处修改所引起的副作用,又可以使函数基于前一次调用的值继续工作。,49/76,例4.15 一个增量函数的应用,void increament(void); void main(void) increament(); increament(); increament(); void increament(void) static int x=0; x+; printf(%dn,x); ,1 2 3,50/76,int i=1; void other(void); void main(void) static int a; int b=-10, c=0; printf(i=%d,a=%d,b=%d,c=%dn,i,a,b,c); c+=8;other(); printf(i=%d,a=%d,b=%d,c=%dn,i,a,b,c); i+=10;other(); void other() static int a=2,b; int c=10; a+=2;i+=4;c+=5; printf(i=%d,a=%d,b=%d,c=%dn,i,a,b,c); b=a; ,i=1,a=0,b=-10,c=0 i=5,a=4,b=0,c=15 i=5,a=0,b=-10,c=8 i=19,a=6,b=4,c=15,51/76,3.静态全局类型,在多文件程序中,未用static声明的外部变量的作用域是整个程序。 用static声明的外部变量,其作用域仅限于所在文件。 例如,当多个函数需要共同使用一个全局变量时,可以将这些个函数组织在同一文件中,而将该全局变量定义为静态的,保证文件的独立性。,52/76,例4.16 随机数函数,static unsigned int r; random(void) r=(r*123+59)%65536; return(r); unsigned random_start(unsigned int seed) r=seed; void main(void) int i,n; printf(Please enter the seed:); scanf(%d, ,53/76,4. 外部变量的定义与声明,对于非静态外部变量,除了可以定义一次外部变量之外,还可以多次进行声明(引用性声明)。 (1)通过声明将外部变量的作用域在本文件 范围内扩充向前引用 (2)利用声明将作用域扩大至其他文件 建立外部链接 (3)全局变量的副作用,54/76,例4.17 外部变量(1)向前引用,void gx(void),gy(void); void main(void) extern int x,y; printf(1:x=%dty=%dn,x,y); y=246; gx(); gy(); void gx(void) extern int x,y; x=135; printf(2:x=%dty=%dn,x,y); int x,y; void gy(void) printf(3:x=%dty=%dn,x,y); ,1:x=0 y=0 2:x=135 y=246 3:x=135 y=246,55/76,例4.18 外部变量(2)外部链接,/111.c int x,y; char ch; main() x=12; y=24; f1(); printf(%cn,ch); ,/222.c extern int x,y; extern char ch; void f1(void) printf(%d,%dn,x,y); ch=a; ,12,24 a,56/76,例4.19 外部变量(4)副作用,void prt(void); int i; void main(void) for(i=0;i5;i+) prt(); void prt(void) for(i=0;i5;i+) printf(%c,*); printf(n); ,57/76,4.2.3通过const声明将变量存储在只读区,定义只读变量的方法是在声明变量时使用修饰符const。 例如,使用定义: const double PI=3.14159; 之后,变量PI的值在程序中就是不可修改的,58/76,4.3 模块的编译与链接,4.3.1 分别编译 4.3.2 用项目管理多文件程序 的编译与链接过程 4.3.3 头文件,59/76,4.3.1 分别编译,4.3.1 分别编译 C语言是一种支持模块化程序设计的语言, 它允许将一个大型程序分成多个程序文件分别 进行编译。这样做的好处有以下几点。 (1)当程序的局部存在错误或对局部进行了修 改时,可以只重新编译该局部部分,无需将整 个程序都重新编译。 (2)某些经过考验的函数的目标代码可以添加 为库函数,供其他程序使用。,60/76,例4.20,要求:从键盘上输入一个字符,若它是数字字符,则输出其ASCll码的平方根的2倍。,61/76,/文件two_sqrt.h extern double two_sqrt(int);,/文件mymain.c #include #include #include isdigit.h #include two_sqrt.h int main(void) char c; printf(Enter a character:); scanf(%c, ,/文件two_sqrt.c #include double two_sqrt(int x) return(2*sqrt(x); ,/文件digit.c #include isdigit.h int is_digit(char ch) return (ch=0 ,/文件is_digit.h #define FALSE 0 #define TRUE 1 extern int is_digit(char ch);,62/76,4.3.2用项目管理多文件程序的编译与链接过程,多文件程序的编译与链接过程是比较麻烦的。 为了便于用户进行多文件程序的编译与链接,各种程序开发软件都提供了用项目(project)管理多文件程序的编译与链接过程。 在C+中,用“工程工作区”来组织程序 In Visual C+, you organize your projects and their elements in a project workspace. A project workspace can contain multiple projects.,63/76,4.3.3 头文件,格式1: #include 只在系统目录中寻找 格式2: #include 文件标识 首先在指定的目录中寻找;若没找到,则按系统目录寻找 头文件中一般包括:函数声明、数据声明、常量定义、宏定义和注释等;通常不包含一般函数定义、常量聚集定义。,64/76,文件包含举例,文件“aaa.h”内容为: #define CH a #define STR program #define PRD(x) printf(%dn,x); #define PRC(x) printf(%cn,x); #define PRS(x) printf(%sn,x);,文件“bbb.c”内容为: #include #include aaa.h void main(void) int i=2; PRD(i); PRC(CH); PRS(STR); ,2 a program,65/76,4.4 宏定义与宏替换,4.4.1 字符串宏定义及其基本格式 4.4.2 使用宏定义需要注意的问题 4.4.3 撤销已定义的宏 4.4.4 带参数的宏定义,66/76,4.4.1 字符串宏定义及其基本格式,#define的基本应用是将一个字符串定义为一个宏名,格式为: #define 宏名 宏体 使用宏替换的优点 提高程序的可读性 提高程序的可维护性 例题:已知半径r,圆柱高h,求圆柱体的侧面积x、全面积y和体积z。,67/76,#define PI 3.14 void main(void) float r,h,x,y,z; r=1.2;h=3.5; x=2*PI*r*h; y=2*PI*r*(h+r); z=PI*r*r*h; printf(%f,%f,%fn,x,y,z); ,68/76,例4.21,#include #define BEGIN #define END void main(void) BEGIN int i,j; float x,y; scanf(%d%d%f%f, END,69/76,4.4.3 撤销已定义的宏,用#undef可以撤销已定义的宏,#include #define BEGIN #define END void main(void) BEGIN int i,j; float x,y; scanf(%d%d%f%f, END,#undef BEGIN #undef END void spc(int n) int i; for(i=0;in;i+) printf( ); return; ,70/76,4.4.4 带参数的宏,#define 宏名(形参表) 宏体,71/76,#define CH a #define AB1 1 #define AB2 2 #define STR program #define MM(a,b) (a)*2+(b) #define PRD(x) printf(%dn,x); #define PRC(x) printf(%cn,x); #define PRS(x) printf(%sn,x); main() int i,j,k; i=2; j=6; k=2*MM(i,j)+5; PRD(k); PRC(CH); PRS(STR); ,25 a program,72/76,例4.22,宏定义: #define SQUARE(x) x*x #define SQUARE(x) (x*x) #define SQUARE(x) (x)*(x) #define SQUARE(x) (x)*(x) 测试 (1) a=SQUARE(n+1) (2) a=16/SQUARE(2),73/76,带参数的宏定义和函数的比较 时空效率不同 执行过程完全不同,宏调用不可递归 错误例: #define FACT(n) (n)=1)?1:FACT(n)-1) main() int m=5; printf(fact %d=%d,m,FACT(m); ,74/76,宏替换的副作用,long square(int n); void main(void) int i=1; while(i=5) printf(%d , square(i+); long square(int n) return(n*n);,1 4 9 16 25,#define square(n) (n)*(n) void main(void) int i=1; while(i=5) printf(%d , square(i+); ,1 9 25,75/76,宏定义命令注意事项, 宏名与宏体之间用以空格相隔,宏名中不能含有空格 #define A NAMES SMISS 宏名不能用双引号括起来 #define YES 1 #define PI 3.14159 printf(PI=%dn,PI); 执行结果: PI=3.14159 而不是: 3.1459=3.14159 对带参数的宏定义,宏体及其各个形参要用括号括起来 宏定义可写在源程序中的任何地方,但应在引用点之前,另外,宏不能重名 习惯用大写字母表示宏名,76/76,本章作业,4.3(1)(2)、4.5、4.7、4.10 (要求抄题) 提示: 4.5题:要求计算Ackermann(1,3)的数值, 不必显示计算过程 4.7题:不必指出变量的存储属性,只要求 写出程序的执行结果,
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


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

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


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