您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 冶金工业 > C语言程序设计课件第7章-模块化程序设计相关
2020/1/191C语言程序设计2020/1/192第七章模块化程序设计相关主讲:计算机学院2020/1/193内容提要程序可以由多个源文件(多模块)组成,使变量的作用域和函数的调用范围被拓广了,产生下面两组概念:•全局外部函数与静态外部函数•全局外部变量与静态外部变量const常类型的有关知识,了解指向const常量的指针作形参既高效又保证了对应实参变量不被修改几种常用的编译预处理•无参宏指令和带参宏指令•条件编译指令•文件包含指令模块化程序设计方法简介,一个管理系统的模块划分2020/1/194从多函数到多模块多函数必定导致多模块:•一个程序如果定义有很多函数,为了便于控制,可以把这些函数按类划分,每一类包含在一个可以独立编译的源文件中,每个源文件称为一个模块•主控模块:是包含主函数的模块,程序永远只有一个主函数多模块必定引起下列问题:•一个变量在某一个模块中定义,可能用于多个模块中•一个函数在某一个模块中定义,可能在多个模块中被调用•当变量或函数需要在其他非定义的模块中使用时,必须作声明,可以在多个模块中声明,但只能在一个模块中定义•当变量空间通过指针被多个模块共享时,如何保护数据•多个文件如何构成同一个程序当程序只有一个模块时,声明和定义的区别常常被忽略2020/1/195全局外部函数函数定义和函数声明的区别:•函数声明(也称函数原型)是向编译器表示一个函数的名称、将接受什么样的参数、有什么样的返回值,使编译器能够检查函数调用的合法性,不为函数分配空间。•函数定义要求编译器生成函数代码,并为之分配存储空间。在多模块程序设计中某函数可以被多个模块调用:•它的声明可以出现在多个模块中•它的定义只能出现在一个模块中全局外部函数:该函数在模块B中定义,但是在模块A中需要调用,则必须在模块A中声明模块B中的该函数,形式:extern返回类型函数名(形参表);这就是同一模块中的函数原型声明形式此关键字表明所声明的函数在其他模块中定义2020/1/196全局外部函数全局外部函数声明的位置(设模块B中定义的函数被模块A所调用):•(1)在模块A的所有函数之外(一般最前面)声明表7.2全局外部函数示例•(2)在模块A的某个需要调用全局外部函数的函数体内声明表7.3在函数体内声明的全局外部函数特别提醒:•⑴全局外部函数定义前不能带关键字extern。•⑵当全局外部函数声明和定义在同一个模块时,外部函数声明前的关键字extern可以省略,例如表7.3中的F函数。动态演示过程动态演示过程2020/1/197静态外部函数静态外部函数:只限于一个模块调用(其他模块不能调用)的外部函数,,也称其为内部函数。静态外部函数在函数体外声明,声明前带有关键字static,定义之前不能带static静态外部函数的定义和声明都必须在调用它的同一个模块中。静态外部函数只能用于1个文件中,具有文件作用域表7.4静态外部函数示例•该例中,有三个模块,两个全局外部函数A和B,一个静态外部函数F,只在Main.c文件中起作用,一个main函数动态演示过程程序只有一个模块时,无所谓静态或全局外部函数,它们是一样的,声明不需要关键字static或extern。定义静态外部函数可以避免和其他模块中的同名函数发生冲突2020/1/198全局外部变量变量定义和变量声明的区别:•变量声明:向编译器表示一个变量的名称和类型,并不为其分配空间,在需要使用变量的模块中都要作出声明•变量定义:根据变量所属类型,为其分配特定大小的内存空间,数据存储格式也随之确定,每个变量只能定义一次•二者关系:只有一个模块的程序中变量的定义和声明是不分的,它们格式相同,定义也就是声明在多模块程序设计中一个变量可以被多个模块使用:•变量声明可以出现在多个模块中•变量定义只能出现在一个模块中并初始化(默认初值为0)2020/1/199函数的定义与调用全局外部变量:该变量在模块B中定义,但是在模块A中需要使用,则必须在模块A中声明模块B中的该变量,形式:extern类型名变量名;全局外部变量声明的位置(设模块B中定义的变量在模块A中被使用):•(1)在模块A的所有函数之外(一般最前面)声明表7.5全局外部变量的全局作用域(演示版作了简化)该例中有一个全局外部变量,数组dys•(2)在模块A的某个需要使用全局外部变量的函数体内声明此关键字表明所声明的变量在其他模块中定义,语法上可以省略,但不建议这样做,避免阅读和理解上的困难这就是变量定义的形式动态演示过程2020/1/1910静态外部变量静态外部变量:只限于一个模块使用(其他模块不能使用)的外部函数静态外部变量在函数体外声明,声明前带有关键字static,这时的声明也就是定义,需要同时作初始化(默认初值为0)静态外部变量只能用于1个文件中,具有文件作用域当某个具有文件作用域的变量在函数内部用static声明(定义)时,就是6.4.2节所讲的静态局部变量了表7.6具有文件作用域的外部变量动态演示过程2020/1/1911各种变量的作用域与生存期变量的存储类型函数内函数外文件外作用域与生存期是否一致作用域生存期作用域生存期作用域生存期(自动)局部变量√√××××一致静态局部变量√√×√×√不一致寄存器变量√√××××一致(静态)外部变量√√√√××一致全局外部变量√√√√√√一致2020/1/1912const常类型(选讲)const常类型存在的必要性:一组数据通过在函数调用过程中传址,实现了其空间的共享。如果该数据只能读取,不能修改,即该数据空间是只读共享的,而在程序运行过程中,却被某个函数通过指针的间接访问修改,运行结果很可能不对对于这类语义错误,要找到并修改这种错误就不容易了,尤其在多模块程序设计中。在传址时对形参指针用const限定修饰符便可保护实参变量不被修改将语义错误转化为语法错误处理就容易得多2020/1/1913const常量(选讲)const常量:变量在声明中带有修饰符const,也称为只读常量。特点:在定义的同时必须初始化,而且初始化之后,其值不能改变,是“只读”性数据定义格式为:•const类型标识符变量标识符=初始化数据;•或类型标识符const变量标识符=初始化数据;特殊地,与指针变量相关的有两个值:•指针本身的值,即指针所存储的地址值•指针所指向的内存空间中的值,即通过指针间接访问的值•例:inta=1,*p=&a;这时与p有关的是p和*pp和*p两个值2020/1/1914const常量(选讲)在定义指针时根据const与指针相对位置的不同,有三种指针:(1)指向const常量的指针,例:constint*pc;(2)const常量指针,例:inta=5;int*constpc=&a;(3)指向const常量的const常量指针,例:inta[5]={2,4,6,8,10};constint*constpc=a;指针作形参时一个常见用法:voidDisplay(constint*pa,intn);//输出函数主调函数:inta[3]={23,45,12};Display(a,3);pc是变量,但是pc所指向的内容*pc不允许修改,通常用于作函数的形参,以保护对应实参变量不被修改pc是const常量,一定要初始化,但是pc所指向的内容*pc不是常量允许修改pc是const常量,一定要初始化,同叶pc所指向的内容*pc也允许修改动态演示(1)过程此函数中一定不能出现通过指针pa修改对应实参数组元素的语句,如:pa[i]=10;*pa=1;等2020/1/1915编译预处理编译预处理:就是执行程序中的预处理指令何时进行:是编辑与编译之间的一步意义:可以优化程序结构,提高程序的效率形式:预处理指令一般以#开头,它不是程序的语句,结尾不带分号分类:有三种编译预处理指令(1)宏定义指令(2)条件编译指令(3)文件包含指令无参宏指令带参宏指令2020/1/1916无参宏指令作用:指定一个标识符代表一个字符串形式:#define宏名宏体举例:表7.8定义了三个无参宏,通过演示观察编译预处理的方式总结:•(1)在源程序中宏名出现之处以宏体内容原样替换•(2)宏没有类型的区分,因此在宏替换时也不作类型的检查•(3)宏体被替换到源程序中之后,在特定位置才作类型上的解释,如本例中的3.1415926在表达式中才被理解为一个double型的字面值常量宏名为用户自定义标识符,通常由大写字母组成宏体理解为一个字符串,不作类型上的解释,在源程序中遇到宏名时直接以宏体内容代入,再作类型上的解释不是语句,最后不能以分号结束动态演示过程2020/1/1917带参宏指令作用:完成一些简单函数所能实现的功能,同时又减少系统开销形式:#define宏名(形参表)宏体举例:表7.9定义了三个带参宏,通过演示观察编译预处理的方式总结:•(1)宏体中包含num的括号是非常重要的,否则展开时易错例如:#definerandom(num)rand()%num则a=random(2+8)被展开成a=rand()%2+8,与要求不符•(2)宏体可以占用多行,需在当前行最后加右斜杠‘\’标识•(3)整个函数或程序都可以做宏体,这时,整个程序简化为一条宏替换命令形参名也是用户自定义标识符,形参表中只有形参名,不可以为形参指定类型宏体中凡是涉及形参名的地方最好都用小括号括起,这样做能保证宏展开后不发生歧义不是语句,最后不能以分号结束动态演示过程宏体中的形参名两边无括号多行演示过程整体演示过程2020/1/1918条件编译指令作用:“插入”和“删除”测试性语句,观察一些变量的值,以检测程序的正确性有两种条件编译指令第一种条件编译指令格式为:•#ifdef宏名•程序段1•#else•程序段2•#endif•含义:如果宏名已经定义,则编译程序段1,否则,编译程序段2。else部分也可以省略。程序7.1条件编译指令测试例(第一种)二#ifndef没有此例只要去掉第一行宏名DEBUG定义(#defineDEBUG),测试语句就不再编译,相当于被删除该宏名如果定义,一般在程序开头动态演示过程2020/1/1919文件包含指令作用:包含系统文件和用户自定义的文件(一般为.h头文件)功能:在编译预处理时,用文件包含指令中所指定的文件名的文本内容来替代该命令,使包含文件的内容成为本程序的一部分。文件包含命令的两种格式为:•(1)#include文件名•(2)#include”文件名”以上两种格式在寻找被包含文件的方式上的区别:先到命令行指定的目录中查找文件;如果没找到,则查找系统定义的标准目录(一般为include目录),不查找当前工作目录,多用于包含标准头文件先到当前工作目录中查找文件;如果没找到,则继续查找命令行定义的其他目录;如果还没找到,则查找系统定义的标准目录。这种格式多用于包含用户自定义的头文件。2020/1/1920文件包含指令用户函数所在文件的定义方式可以:•(1)把一类函数的原型放在一个.h头文件中•(2)将对应的函数定义放在主文件名相同的.c文件中构成一个模块•含有函数原型的头文件可以出现在任何模块中;而含有函数定义的文件只能出现在程序的一个模块中。为了避免重复包含,头文件前后应该加条件编译指令•例如:假设头文件名为utility.h,文件格式为:•#ifndefUTILITY_H•#defineUTILITY_H•函数原型•#endif程序7.2:用文件包含的方式实现表7.5所示的程序,功能为输出平年的每月天数和一年总天数。请在VC++下演示整个程序!动态演示过程2020/1/1921模块化程序设计方法简介基本策略:大化小,小化了!模块化程序设计的几个特点:•(1)可分模块单独开发,整个程序的开发时间缩短•(2)开发一个模块无需知道其他模块的内部结构和编程细节•(3)模块之间的接口尽可能简明,模块应尽可能彼此隔离。•(4)具有可修
本文标题:C语言程序设计课件第7章-模块化程序设计相关
链接地址:https://www.777doc.com/doc-3180450 .html