C语言模块化程序设计.ppt
《C语言模块化程序设计.ppt》由会员分享,可在线阅读,更多相关《C语言模块化程序设计.ppt(57页珍藏版)》请在装配图网上搜索。
1 第4章模块化程序设计 北京交通大学计算机学院赵宏 2 教学目标 理解如何用函数模块构造程序熟悉标准库中常见的函数会定义和调用函数并理解函数调用的机制掌握变量的作用域和存储类别理解并运用递归函数编写程序 3 4 1模块化程序设计概述4 2函数的声明 定义和调用4 3函数的多级调用4 4变量的作用域和存储类别4 5计算机随机模拟方法4 6编译预处理 4 复杂任务可以分解为若干子任务 重复使用的程序段 将其进行独立设计 使计算机可以重复执行 4 1模块化程序设计概述 5 1 引例 4 2函数的声明 定义和调用 程序名 4 1 cpp 功能 计算两个实数中大的值 includefloatfmax floatx floaty 函数说明 voidmain floata b c scanf f f floatfmax floatx floaty 函数定义 floatz z x y x y returnz 6 2 函数说明 说明格式为 函数返回值类型函数名 参数表 includefloatfmax floatx floaty 函数说明 voidmain floata b c scanf f f 函数说明是一条语句 它指出函数返回值的类型 函数的名称 函数要接收的参数的个数 顺序和类型 如果在一个函数中要调用另外一个函数 则在调用之前要对该函数进行说明 4 2函数的声明 定义和调用 7 3 函数定义 函数定义的一般形式 函数值类型函数名 形参表 函数头 函数体 说明部分执行部分 4 2函数的声明 定义和调用 floatfmax floatx floaty floatz z x y x y returnz 函数头 函数体 8 4 函数调用 函数调用的一般形式为 函数名 实参表 4 2函数的声明 定义和调用 voidmain floata b c scanf f f 可用两种方式调用函数 1 函数的调用可以在允许表达式出现的任何地方 如 c fmax a b 2 函数调用可以作为一条独立的语句 比如 有函数定义 voidprintstar printf 则可以把该函数调用作为一个独立语句 printstar 9 4 2函数的声明 定义和调用 函数返回值函数返回值的类型是由函数定义或说明中的函数返回类型决定的 如果返回的类型与函数说明的不同 则在返回值时 先作隐含的类型转换 然后再返回 includeintfmax floatx floaty returnx y x y voidmain floatmax max fmax 3 5 2 6 printf max f n max 结果 10 4 2函数的声明 定义和调用 形参和实参形式参数 定义函数时放在函数名称之后括号中的参数 简称形参 实际参数 调用函数时括号中的参数 简称实参 形参与实参的结合 函数在调用时 将生成实参值的一个副本传递给对应的形参 这个过程称为形参与实参的结合 如果只允许实参向形参传递数据 则被称为 单向传递 11 4 2函数的声明 定义和调用 参数传递实例 voidswap floatx floaty floatt t x x y y t voidmain floata b scanf f f 12 4 2函数的声明 定义和调用 函数的调用过程 voidmain floata b c scanf f f floatfmax floatx floaty floatz z x y x y returnz 保存返回地址及当前现场 为形参分配内存并将实参的值传给形参变量 恢复main函数的现场 取得返回地址和返回值 13 4 带自定义函数的程序设计 4 2函数的声明 定义和调用 程序设计思路 1 定义一个函数isprime intm 判断m是否为素数 若是素数 函数返回1 否则返回0 intisprime intm inti for i 2 i m 1 i if m i 0 return0 return1 2 在主函数中输入一个整数 调用isprime函数 如果函数值为1 则打印是素数 否则打印不是素数 voidmain intiNumber printf 请输入一个整数 scanf d 例4 2 从键盘输入一个整数 判断该整数是否为素数 14 1 嵌套调用 intmin2 inta intb returna b a b intmin3 inta intb intc intx y x min2 a b y min2 t c returny includevoidmain intt1 t2 t1 min2 2 8 printf min d n t1 t2 min3 2 8 6 printf min d n t2 4 3函数的多级调用 15 4 3函数的多级调用 main函数 t1 min2 2 8 t2 min3 2 8 6 min3函数 x min2 a b min2函数 returna b a b 图4 5函数调用关系 16 1 嵌套调用 续 例4 5 用弦截法求方程x3 5x2 16x 80 0的根 4 3函数的多级调用 求解的方法是 17 程序设计思路 1 输入x1 x2代表根的初始区间 f1 f2代表函数f在x1 x2两点的函数值 要保证初始的f1 f2异号 如果不是异号 要重新输入x1 x2 2 定义函数f x 计算多项式f x x3 5x2 16x 80的值 3 用函数xpoint x1 x2 计算f x1 f x1 和f x2 f x2 的连线与x轴交点x的值 公式为 4 定义函数root x1 x2 来求解实根 首先调用用函数xpoint x1 x2 计算f x1 f x1 和f x2 f x2 的连线与x轴交点x的值 再判断f x 与f x1 和f x2 哪一个同号 如果f x 与f x1 同号 就用x作为新的x1 否则就用x作为新的x2 再在新的区间内进行计算 4 3函数的多级调用 18 4 3函数的多级调用 19 2 递归调用 递归调用指的是一个函数执行过程中出现了直接或间接调用函数本身的调用方式 如果直接调用函数本身称为直接递归 如果调用了另外一个函数 那个函数又调用该函数 则称为间接递归 递归方法的基本思想是将一个问题向下分解具有同样解决方法但规模不断缩小的子问题 不断进行这样的分解 直到分解的子问题有一个已知解 某数列为k n 的定义为 1n 1k n 2 k n 1 n为偶数3 k n 1 n为奇数 4 3函数的多级调用 20 4 3函数的多级调用 k 4 k 3 2 k 3 k 2 3 k 2 k 1 2 k 1 1 k 2 1 2 2 k 3 2 3 6 k 4 6 2 12 图4 6回推和递推过程 21 intk intn 递归计算函数 intm m存放函数的返回值 if n 1 m 1 elseif n 2 0 m k n 1 2 调用自身 n为偶数 elsem k n 1 3 调用自身 n为奇数 return m voidmain printf nk d f k 4 4 3函数的多级调用 22 例4 6 求Fibonacci数列第n项的值 Fibonacci数列以1 1开头 以后每一项都是前两项之和 1 1 2 3 5 8 13 21 程序设计思路 1 求Fibonacci数列第n项的值可用递归形式定义为 fibonacci 0 1fibonacci 1 1fibonacci n fibonacci n 1 fibonacci n 2 2 定义fibonacci函数计算第n项的值intfibonacci intn if n 0 n 1 return1 elsereturnfibonacci n 1 fibonacci n 2 4 3函数的多级调用 3 递归调用举例 23 例4 8 反向输出一个长整数程序设计思路 1 如果要输出的数据只有一位 则 反向输出 问题可简化为输出一位整数 2 如果要输出的数据超过一位 则可将该整数分为两部分 个位上的数字和个位以前的数字 个位上的数字可以直接输出 而个位以前的数字又可以看成一个新的整数 重复执行 反向输出 的操作 这时 反向输出在规模上缩小了一位 但求解的方法还是一致的 3 用表达式x 10可以分离出一个整数个位上的数字 用表达式x 10可以表示出个位以前的数 定义一个反向输出函数invertLongInt 每次先用x 10计算并输出个位上的数 然后用x 10 即个位以前的数 做参数调用自己 不断进行下去 直到只剩一位数字 4 3函数的多级调用 24 递归函数可以写为 voidinvertLongInt longx if x 0 4 3函数的多级调用 25 小结 函数分为系统函数和自定义函数 每个函数的都是独立定义的 如果函数定义在后 调用在前 要对函数原型进行说明 除了主函数外 其他函数可以相互调用 如果A调用B B又调用C 称为嵌套调用 如果直接或间接调用自己 称为递归 26 练习 函数fun实现计算两个数之差的绝对值 并将差值返回调用函数 请编写fun函数fun intx inty 27 第7周作业 1 在主函数中输入三角形的的三条边 调用子函数 判断是否能组成三角形 若可以则返回1否则返回0 在主函数中输出判断结果 2 编写函数 求两个正整数m和n的最大公约数 m和n作为函数的参数 函数返回运算结果 由主函数输出 4 习题4 2要求 第8周上课前提交 28 1 程序区 存放用户程序代码 即程序中各个函数的代码 2 静态存储区 存放程序的全局数据和静态数据 分配在静态存储区中的变量的生命期最长 它们在main函数运行之前就存在了 在程序的整个活动期 从程序开始执行到执行结束 中 这些变量始终占用静态存储区中对应的存储空间 即程序开始执行时分配存储单元 程序执行完毕后释放 3 动态存储区 存放局部变量 分配在动态存储区中的变量只有在所定义的函数被调用时才分配存储单元 函数结束时就释放 系统对函数调用时的现场保护 返回地址等也占用动态保护区 4 堆 自由存储区 用于运行程序时动态申请内存 4 4变量的作用域和存储类别 1 程序在内存中的分布区域 29 局部变量 在块内定义的变量 局部变量作用域 块内定义 块内使用 所谓块内是指一对以 为界限的若干个语句 例如函数体 复合语句 而块内使用 是指变量的作用范围仅仅局限在从变量定义处开始 到变量定义所在的那个块结束 如 4 4变量的作用域和存储类别 2 局部变量及存储类别 局部于main的局部变量 局部于func的局部变量 voidmain intn 5 printf d n func voidfunc intn 8 printf d n 30 形式参数也为局部变量 其作用范围是形式参数所在的整个函数 例如 voidmain printf d d x y error voidfunc intx inty 4 4变量的作用域和存储类别 31 局部变量的存储类别 自动变量 用关键字auto 可缺省 加以说明的局部变量 如 autofloatb 或floatb 特点 是短生命期的局部变量 安排在动态存储区 由系统自动分配和释放 用到时分配内存 不用时释放内存 以节省程序执行时的内存资源 局部静态变量 用关键字static加以说明的局部变量 局部静态变量在静态存储区分配空间 如 staticintcount 特点 是长生命期的局部变量 函数执行结束后 分配给该变量的存储区不释放 局部静态变量安排在静态存储区 寄存器变量 用关键字register说明的局部变量为寄存器变量 特点 寄存器变量的值存放在CPU的寄存器中 可以提高程序的执行效率 4 4变量的作用域和存储类别 32 例4 10 局部变量存储方式举例 分析下面程序运行结果 程序名 4 10 cpp 功能 局部变量存储方式示例 includeintfun1 int intfun2 int voidmain inti for i 2 i 5 i printf fun1 d d t i fun1 i printf n for i 2 i 5 i printf fun2 d d t i fun2 i printf n 4 4变量的作用域和存储类别 33 续上页 intfun1 intx intf 1 return f x intfun2 intx staticintf 1 return f x 4 4变量的作用域和存储类别 程序执行结果为 fun1 2 2fun1 3 3fun1 4 4fun2 2 2fun2 3 6fun2 4 24 34 includeintfunc int int voidmain intk 4 m 1 p p func k m printf d p p func k m printf d n p intfunc inta intb staticintm i 2 i m 1 m i a b return m 结果 8 17 主函数 第一次fun函数 k m 4 1 m i 0 2 m i 8 3 第二次fun函数 m i 8 3 m i 17 12 35 全局部变量 函数外定义的变量 全局变量作用域 全局变量的作用范围是从变量定义处开始到所定义的源文件结束处 即从全局变量定义所在处开始到源文件结束处之间的所有函数都可以访问该变量 如 intn 1 voidmain printf d n func printf d n floatm voidfunc n 5 m 3 4 4变量的作用域和存储类别 2 全局部变量及存储类别 36 例4 11 全局变量的作用域举例 分析下面程序运行结果 includevoidswap void inta b 是两个函数公用的变量 voidmain scanf d d 使用的变量名a和b全局变量a和b 4 4变量的作用域和存储类别 37 局部变量与全局变量同名时的处理 小范围优先 例4 12 分析下面程序运行结果 inti 1 变量i定义在所有函数之外 属于全局变量 voidmain printf 主函数中访问的变量i d n i i test 1 printf 主函数中访问的变量i d n i inttest inti printf test中访问的变量i d n i i 2 printf test中访问的变量i d n i returni 4 4变量的作用域和存储类别 程序运行结果 主函数中访问的变量i 1test中访问的变量i 28345test中访问的变量i 2主函数中访问的变量i 3 38 全局部变量的存储类别 静态全局变量 使用关键字static定义的全局变量是文件内部的全局变量 特点 只能被定义所在的源文件中的所有函数访问 同一程序的其它源文件中的函数都不能访问该变量 非静态全局变量 使用缺省关键字的全局变量 特点 则该变量不仅能被定义所在的源文件中的所有函数访问 而且组成程序的其它源文件中的所有函数也都能访问该变量 因此 从作用范围看 缺省关键字的全局变量要比使用关键字static的静态全局变量大 关键字extern的作用关键字extern的作用是对要使用的某个尚未定义的全局变量在使用前作变量说明 该全局变量或者是以后会在该源文件中定义的全局变量 或者是在另一个源文件中使用缺省关键字定义的全局变量 4 4变量的作用域和存储类别 39 例4 13 全局变量存储方式举例 分析下面程序运行结果 程序名 4 13 cpp 功能 全局变量存储方式示例 includeexterninta 对4 13 2 cpp中定义的变量进行说明 voidfun1 voidfun2 voidmain fun1 fun2 printf 函数main中的a是 d n a 4 4变量的作用域和存储类别 40 程序名 4 13 1 cpp includestaticinta 只允许文件4 13 1 cpp中函数访问的全局变量 voidfun1 a 2 printf 函数fun1中的a是 d n a 程序名 4 13 2 cpp includeinta 允许其它文件中函数访问的全局变量 voidfun2 a 4 printf 函数fun2中的a是 d n a 4 4变量的作用域和存储类别 41 rand 函数可随机生成0 RAND MAX之间的一个整数 RAND MAX是头文件中定义的一个符号常量 ANSI规定RAND MAX的值不小于32767 根据下面公式可以得到所需范围内的随机数 n a rand b其中a为位移 是所需连续整数范围的第一个数 b是比例因子 是所需连续整数范围的宽度 则希望产生1 6之间随机数的公式为 face 1 rand 6 4 5计算机随机模拟方法 1 伪随机数的产生 42 例4 14 编写一个模拟投掷硬币的程序 模拟20次 统计出正面出现的次数 include includevoidmain inti face iCount 0 for i 1 i 20 i face rand 2 printf 5d face if i 10 0 printf n if face iCount printf 正面出现次数 d次 n iCount 4 5计算机随机模拟方法 43 运行程序 结果为 11001000001111111010正面出现次数 11次再次运行该程序结果为 11001000001111111010 4 5计算机随机模拟方法 44 用srand 函数进行随机化voidmain unsignedseed printf 输入一个非负整数做种子 scanf d 运行3次程序 输入一个非负整数做种子 161343565262输入一个非负整数做种子 333153565415输入一个非负整数做种子 161343565262 4 5计算机随机模拟方法 45 使用系统定时 计数器的值做为随机种子 srand time NULL time 函数返回以秒为单位的当前时间值 因为有时钟参数 而时间始终在变 随机数序列就不会固定不变了 例4 16 编写程序 用来生成一个随机小写字符串 include include includevoidmain srand time NULL for inti 1 i 20 i printf c 97 rand 26 4 5计算机随机模拟方法 46 用事件发生的 频率 来决定事件的 概率 考虑平面上的一个边长为1的正方形及其内部的一个形状不规则的 图形 如何求出这个 图形 的面积呢 MonteCarlo方法是这样一种 随机化 的方法 向该正方形 随机地 投掷N个点落于 图形 内 则该 图形 的面积近似为M N 例4 17 计算图形面积 图中有两条半径为1的圆弧 求s的面积 4 5计算机随机模拟方法 2 蒙特卡罗 MonteCarlo 方法 x y o 1 1 s 图4 10求面积 47 程序设计思路 模拟雨点落在阴影区域的情况 对于以x 0 y 0位圆心的圆 s中每个点应该满足 1 对于以x 1 y 0位圆心的圆 s中每个点应该满足 2 同时满足 1 和 2 就可以保证雨点落在s区域 可以使用如下语句 if sqrt x x y y 1g为落入s区雨点的数目 程序参见教材4 17 cpp 4 5计算机随机模拟方法 48 文件包含 是指一个源文件可以将另一个源文件的全部内容包含进来 在编译预处理时 include指令让预处理器在程序该点处加入指定文件内容 然后作为一个源文件编译形成新文件 文件包含的一般形式为 1 include 2 include 文件名 例如 include include stdio h 4 6编译预处理 1 文件包含 include 49 1 定义符号常量 define标识符字符串如 definePI3 14预处理器将在源文件中搜索PI 并把每个PI替换成3 14 完成搜索和操作替换后 预处理器删除 define行 2 定义宏 define宏名 参数表 字符串如 defineS a b a b对程序中带有实参的宏 如S 3 4 按 define命令中指定的字符串从左到右进行替换 如果字符串中包含宏的形参 如a b 则将程序语句中相应的实参代替形参 如果宏定义中字符串中的字符不是参数字符 如a b中的 则原样保留 4 6编译预处理 2 宏定义 define 50 3 宏与函数宏替换只占编译时间 不占运行时间 但函数调用时分配单元 传值 返回值时都占时间 特别是多次调用时尤为严重 但使用宏的程序代码较长 因为宏在程序中存在了多次 而使用函数时 虽然多次调用 但函数代码只存在一次 函数调用时先求实参表达式的值 再传给形参 而带参数的宏只是简单的字符替换 宏展开时并不对实参表达式求值 函数调用时临时分配存储单元 宏替换并不分配存储单元 也没有返回值 宏是无类型的 宏既可以用于浮点型 也可以用于整型 因为预处理器只是完成字符替换 而不考虑它的参数类型 如果使用函数 则对于每种求平方的数据类型都需要一个函数 4 6编译预处理 51 条件编译就是按条件对C C 程序的一部分进行编译 其它部分不编译 1 使源代码能更迅速 更容易地进行修改 并使目标代码缩短 如 if MAX 99 printf Compiledforarraygreaterthan99 n elseprintf Compiledforsmallarray n endif 2 协调多个头文件 避免一个符号或一个头文件被多次包含 例如 符号NULL在几个不同的头文件中都进行了定义 如果一个源文件包含其中几个头文件 则会出现符号NULL被多次定义的错误 这时需要使用条件编译命令 ifdefNULL defineNULL void 0 endif 4 6编译预处理 3 条件编译 52 4 7本章小结 函数分为系统函数和自定义函数 每个函数的都是独立定义的 如果函数定义在后 调用在前 要对函数原型进行说明 除了主函数外 其他函数可以相互调用 如果A调用B B又调用C 称为嵌套调用 如果直接或间接调用自己 称为递归 内存为用户提供的存储空间可以分三类 程序区 静态存储区 动态存储区 从变量占用空间的角度来分析问题 划分出全局变量和局部变量 这是变量的作用域问题 由变量值存在的时间来分析问题 由此划分出了变量的静态存储和动态存储 这是变量的存储类别问题 4 7本章小结 53 思考题 为什么要对函数进行说明 局部变量和全局变量的有效范围都是什么 变量的动态存储和静态存储有何区别 变量的作用域和生存期有什么区别 有什么联系 54 作业 实验二 55 趣味程序 编写程序 帮助小学生学习加减法 用rand 函数产生两个一位数 然后输入下列问题 然后输入答案 程序检查学生的答案 如果正确 则打印 正确 然后提出另外一个加法问题 如果不正确 则打印 错误 让学生重复回答这个问题 直到正确为止 sy4 1 cpp 56 voidmain intk flag 1 while flag 显示菜单 printf 1 加法运算 n printf 2 减法运算 n printf 0 退出 n printf 请输入选项 0 2 scanf d 57 voidadd inta b c m n 0 srand time NULL 随机化随机数序列 while 1 a rand 10 生成两个随机数 和不能超过10 b rand 10 a printf d d a b scanf d n 0 n用来统计计算错误次数 while c a b 允许计算三次 n if n 3 printf 错误 请重计算一次 n printf d d a b scanf d- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 模块化 程序设计
装配图网所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
关于本文