函数与编译预处理.ppt

上传人:max****ui 文档编号:8381956 上传时间:2020-03-28 格式:PPT 页数:75 大小:759.50KB
返回 下载 相关 举报
函数与编译预处理.ppt_第1页
第1页 / 共75页
函数与编译预处理.ppt_第2页
第2页 / 共75页
函数与编译预处理.ppt_第3页
第3页 / 共75页
点击查看更多>>
资源描述
第四章函数与编译预处理 4 1模块化程序设计与函数4 2函数的定义与调用4 3函数的递归调用4 4变量作用域与存储方式4 5编译预处理4 6函数设计举例 教学目的和基本要求 要求学生了解模块化程序设计的思想 掌握函数的定义及调用 理解变量的作用域与存储方式的概念 理解编译预处理的概念 教学重点 函数的定义及调用 递归调用 变量的作用域 4 1模块化程序设计与函数 在设计较复杂的程序时 我们一般采用的方法是 把问题分成几个部分 每部分又可分成更细的若干小部分 逐步细化 直至分解成很容易求解的小问题 这样的话 原来问题的解就可以用这些小问题来表示 把复杂任务细分成多个问题的过程 就叫程序的模块化 模块化程序设计是靠设计函数和调用函数实现的 模块与函数 C语言程序由基本语句和函数组成 每个函数可完成相对独立的任务 依一定的规则调用这些函数 就组成了解决某个特定问题的程序 任务 模块与函数的关系 看这样一个问题 求 200 1000 的双胞胎数的对数 双胞胎数 两素数差为2称为双胞胎数 这是我们上一章结束的一道练习题 下面的左边是我们当时编的程序 main inta b n 0 I for a 200 a 998 a for I 2 I a I if a I 0 break if a i b a 2 for I 2 I b I if b I 0 break if b i n printf n d n 我们注意到 程序中用筐住的部分是完成了相同的功能 即判断一个数 a或b 是否是素数 我们可以考虑用一个独立的函数来完成判断素数的功能 在主函数中调用此函数即可 如下 main inta b n 0 intf intx for a 200 a 998 a if f a 1 b a 2 if f b 1 n printf n d n intf intx intI for I 2 I x I if x I 0 break if x I return1 elsereturn0 下面我们详细介绍函数调用的格式和语法规定 4 2函数的定义与调用 在C语言中 函数 Function 是一个处理过程 可以进行数值运算 信息处理 控制决策 即一段程序的工作放在函数中进行 函数结束时可以携带或不带处理结果 库函数 标准函数 系统提供自定义函数 用户自己写 C语言程序处理过程全部都是以函数形式出现 最简单的程序至少也有一个main函数 函数必须先定义和声明后才能调用 标准库函数 C语言有丰富的库函数 这些函数的说明在不同的头文件 h 中 想要调用标准的库函数 就必须include includemain printf d 1024 768 自定义函数 可以把完成一个任务的过程写成函数 intA to a intcapital intsmall if capital A 函数 的主要知识点 函数的定义函数的参数和返回值函数的调用嵌套和递归变量的作用域 函数举例 includemain inta b m 说明变量 intmax inta intb 函数声明 scanf d d 调用库函数getch 函数举例 intmax inta intb 定义函数max inty y a b a b 条件表达式 returny 自定义函数的声明 自定义函数在调用前应先声明 使系统知道将要用到某个函数及它的类型 以便处理 函数声明应与该函数定义时给出的函数类型与名字 形参的个数 类型 次序相一致 求1 2 3 10 算法i 1 s 0 当i 10s s i 定义求i 的函数 求1 2 3 10 程序 voidmain longmm int 自定义求阶乘函数应先声明 inti longs 0 for i 1 i 10 i s mm i 调用求阶乘函数 求I的阶乘 printf n ld s 定义求n 的函数 longmm intn longt 1 inti for i 1 i n i t i returnt 函数的参数 intmax inta intb inty y a b a b returny 调用时 m max 3 6 m max a b 形式参数与实际参数的关系 形式参数在函数中是变量名 在函数调用时 形参被分配相应的内存实际参数是表达式负责向对应的形参标识的内存单元传递数据实参与形参必须个数相同对应的形参和实参的类型必须一致 实参与形参 例 主调函数中有如下语句 scanf d d 如果输入6 2函数intmax inta intb 形参a得到第一个实际参数a的值6形参b得到第二个实际参数b 3的值5 函数返回值 函数返回值通过return语句获得函数返回值的类型就是函数的类型returny 将变量y的值返回给调用者returny 3 将表达式的值返回给调用者 return的数据类型与函数的类型矛盾时 自动将数据转换成函数的类型 intfunct1 charch while ch getch z returnch 调用 i funct1 返回的是int类型 函数没有返回值 函数定义成空类型 voidputline inti for i 0 i 35 i printf printf n 函数的功能就是输出35个 调用 putline 应该的语句形式i putline 是错的 调用函数 a function x y 或者function x y 取返回值 只是操作 解决更复杂问题时可以嵌套调用 longfac intk longf 1 inti for i 1 i n i f f i retrunf longcombination intn intm longc inti c fac m fac n fac m n retrunc 主函数 main intn m longc scanf d d 理论上可以a b d e x c f 般嵌套无数层 4 3函数的递归调用 函数调用它本身 称为递归 直接在函数内调用自己为直接递归 通过别的函数调用自己为间接递归 voida a voida b voidb a 递归在解决某些问题中 是一个十分有用的方法 因为其一 有的问题它本身就是递归定义的 其二 它可以使某些看起来不易解决的问题变得容易解决 写出的程序较简短 递归方法求n 由于n n n 1 是递归定义所以求n n 1 n 1 n 2 n 2 n 3 0 的问题 根据公式有0 1 再反过来依次求出1 2 直到最后求出n 递归方法求n longfac intn longf if n 0 f 1 elsef n fac n 1 returnf main longy intn scanf d 刚开始的时候 这个n是前面输入的需要阶乘的n 所以在这里带入的值是n 而这个函数里又调用了本身 不过参数已经变成了n 1 所以这里再次调用时参数已经变成了n 1注意 上次调用fac n 还没有完 只是由于遇到了fac n 1 而执行fac n 1 去了 而在调用fac n 1 时同样遇到了要调用fac n 2 的问题 于是一层一层的包裹下去 每次调用的时候都会在内部调用一个结构相同但变量不同的函数 直到 直到调用到fac 0 时 由于内部if判断 已经不需要再继续调用另一个fac n 1 而直接有了f 1 fac 0 已经执行完毕 它的返回值被fac 1 中的f n fac n 1 语句赋给了f值 同时返回了f 而这个返回的f又被fac 2 乘上当前的n值以后继续返回f 直到最后的fac n 都做完了 f的值被返回到了它的调用点 主函数中 这样就是一个递归运算 递归举例 问题 第1个月有1对兔子过2个月 兔子就可每个月生1对兔子问第n个月有多少对兔子 分析 设第n个月有f n 对兔子根据题意有f 0 0 f 1 1f n f n 1 f n 2 f n 1 前一个月的兔子数f n 2 本月生的兔子数 定义函数f n longf intn switch n case0 return0 break case1 return1 break default returnf n 1 f n 2 调用函数f n 兔子问题主函数 voidmain longf intn 自定义函数声明 intn printf ninputn scanf d 调用函数f n 辗转相除法求最大公约数 求m和n的公约数算法if m n 0n是公约数 else求n和m n的公约数 求最大公约数的递归算法 intgcd intm intn if m n 0returnn elsereturngcd n m n 求最大公约数的主函数 voidmain intm n t intgcd intm intn scanf d d 4 4变量作用域与存储方式 先看一个例子 错在那里 voidf1 intt 2 a t b t main inta b printf Entera b scanf d d 编译程序会提示出错 Undefinedsymbol a 和Undefinedsymbol b 为什么 一 变量的作用域即变量的有效范围1 变量按作用域分为全局变量和局部变量2 比较 全局变量 外部变量 局部变量 内部变量 定义位置 函数体外函数体内作用域 从定义处到本源从定义处到本函数结束文件结束举例 所有函数体外定义的变量 1 所有在函数体内定义 2 形式参数 注意与局部变量同名的处理局部变量屏蔽全局变量 不同函数中同名局部变量互不干扰 3 局部变量 C语言程序是由函数组成的 有且只能有一个main函数 变量定义可以出现在函数内 亦可出现在函数外或者是函数的参数中 按照变量定义语句出现的位置 可以分为 局部变量 在函数或复合语句内定义 只在该函数或复合语句中才能使用 全局变量 在函数外定义 从它被定义的位置起 在之后的所有函数中有效 形式参数 定义为函数的参数 只在该函数中才能使用 在函数内部说明的变量或者在复合语句中定义的变量称为局部变量 其作用范围是其所在的函数或复合语句 又称全程变量或外部变量 在函数外部说明 其作用范围从它被定义的位置起 在之后的程序段中都是起作用的 4 全局变量 如果在全局变量定义之前的函数想引用该外部变量 则应该在该函数中用关键字extern作 外部变量说明 inta b voidswap intt t a a b b t printf swap a d b d n a b main printf Entera b scanf d d Entera b 5 3 swap a 3 b 5main a 3 b 5 运行结果 inta b voidswap intt t a a b b t printf swap a d b d n a b main printf Entera b scanf d d 运行结果 inta b 程序在编译时 屏幕将提示有错误 Undefinesymbol a Undefinesymbol b inta b voidswap intt t a a b b t printf swap a d b d n a b main printf Entera b scanf d d 运行结果 inta b inta 5 b 3 Entera b 5 3 swap a 3 b 5main a 5 b 3 includeinta b a b为全局变量 voidf1 intx intt1 t2 a a t1 x 4 t2 b 3 b 10 printf f1 t1 d t2 d a d b d n t1 t2 a b main a 2 b 4 此a b是全局变量 赋值 f1 a 调用函数f1 printf main a d b d a b 程序输出结果为 f1 t1 8 t2 12 a 8 b 10main a 2 b 10 若将程序改为 includeinta 2 b 4 a b为全局变量 voidf1 intt1 t2 t1 a 2 t2 b 3 b 100 printf t1 d t2 d b d n t1 t2 b main intb 4 此b是局部变量 赋值 f1 调用函数f1 printf a d b d a b 结论 全局变量与局部变量同名时 局部变量起作用 全局变量被屏蔽 不影响 应小心使用 程序输出结果为 t1 4 t2 12 b 100a 2 b 4 二 变量的存储特性1 变量按存在时间分静态变量动态变量 静态存储类型的变量的生存期为程序执行的整个过程 在该过程中占有固定的存储空间 通常称它们为永久存储 动态存储类型变量只生存在某一段时间内 例如 函数的形参和函数体或分程序中定义的变量 只是在程序进入该函数或分程序时才分配存储空间 当该函数或分程序执行完后 变量对应的存储空间又被撤销了 2 c语言中每一个变量有两个属性 数据类型 存储特性完整的变量定义 存储特性 数据类型 变量名 3 变量的存储特性自动型auto静态型static寄存器型register外部型extern 1 auto型每次进入程序是自动分配内存 不长期占用内存例如 形式参数 自动型局部变量 2 static型 局部静态变量 全局静态变量长期占用内存 例1 分析执行结果f inta intb 0 staticintc 3 b c printf 5d 5d 5d a b c return a b c main inta 2 k for k 0 k 3 k printf 5d n f a 静态变量只初始化一次 结果 214 a b c 7 f a 21582169 3 register型将使用频率高的变量定义为register型 可以提高运行速度 数据内存运算器运算器结果控制器数据 寄存器 寄存器变量只限于整型 字符型 指针型的局部变量 寄存器变量是动态变量 而且数目有限 一般仅允许说明两个寄存器变量 例如 registerintd registercharc 4 extern型引用 extern类型变量名 如果某个模块文件中要用到另一个模块文件中的全局变量 就要用extern说明例如 程序模块file1 c中定义了全局变量ints 而在另一个程序模块file2 c中的函数fun1 中需要使用这个变量s 为此 可以在file2 c的函数fun1 中加上外部变量说明语句 fun1 externints 表明变量s是在其他文件定义的 定义时分配内存 其他文件引用时不再分配内存 4 5编译预处理 编译预处理 是C语言编译系统的一个组成部分 是在编译前由编译系统中的预处理程序对源程序的预处理命令进行加工 源程序中的预处理命令均以 开头 结束不加分号 以区别源程序中的语句 它们可以写在程序中的任何位置 作用域是自出现点到源程序的末尾 预处理命令包括执行宏定义 宏替换 包含文件和条件编译 一 宏定义简单宏定义1 一般形式为 define宏名串 宏体 如 definePI3 14159 定义后 可以用PI来代替串3 14159 2 宏定义的作用在宏定义之后 该程序中宏名就代表了该字符串 3 说明 可以用 undef命令终止宏定义的作用域 例如 undefPI 宏定义的嵌套使用 defineR3 0 definePI3 1415926 defineL2 PI R 宏体是表达式 defineSPI R R main printf L f nS f n L S 2 PI R替换L PI R R替换S 程序运行结果如下 L 18 849556 双引号内与宏同名的字母不作宏展开 见上例 带参数的宏定义1 带参数的宏定义的一般形式为 define宏名 参数表 字符串如 defineS a b a b definePR x printf s f n x 2 带实参的宏名被展开宏名被所定义的宏体替换 宏体中的形参按从左到右的顺序被实参替换 例如 area S 3 2 PR area 展开为 area 3 2 PR area 展开的结果是 printf s f n area 宏定义与函数的区别 1 引用宏只占编译时间 不占运行时间 2 引用宏没有返回值 如 definesqu n n nvoidmain void printf f n 27 0 squ 3 0 程序输出结果为 27 000000 注意 展开为27 0 3 0 3 0不是27 0 3 0 3 0 3 宏替换的形参无类型 4 实参为表达式的情况函数调用是先计算出实参的值 再将值传递给形参 宏的引用是用表达式替换形参 例如 defineS a b a b引用 S a c b c 展开后的表达式为 a c b c 二 文件包含 include1 文件包含是指一个源文件可以将另一个源文件的全部内容包含进来 2 include命令有两种格式 1 include 2 include 文件名 3 两种格式区别 p102 三 条件编译1 控制条件为常量表达式的条件编译 有以下几种形式 if常量表达式程序段 endif 功能 常量表达式为非 时 程序段被编译 否则 程序段不被编译 if常量表达式程序段 else程序段 endif 功能 常量表达式为非 程序段 被编译 否则 编译程序段 if常量表达式 程序段 elif常量表达式 程序段 elif常量表达式 程序段n else程序段n 1 endif 控制条件为定义标识符的条件编译 ifdef标识符程序段 endif功能 当标识符在该条件编译结构前已定义过时 程序段被编译 否则 程序段不被编译 ifdef标识符程序段 else程序段 endif功能 当标识符在该条件编译结构前已定义过时 程序段 被编译 否则 编译程序段 ifndef标识符程序段 else程序段 endif功能是 当标识符在该条件编译结构之前没有被 define定义过时 程序段 被编译 否则 编译程序段 条件编译举例 defineinttag1Main intch scanf d ch ifinttagprintf d ch elseprintf c ch endif 编译成 main intch scanf d ch printf d ch 1 以下程序求 10 1000 之间能被3或5或8整除的数之和 请将程序补充完整 给出正确程序运行结果 填入相应窗口 include include includemain longsum sum 0 for i 10 i 1000 i if sum i clrscr printf ld n sum 3 下面程序是求 5 75 之间的所有奇数的立方和 请将程序补充完整 并给出正确结果 填入相应窗口 include include includemain longsum sum 0 for i 5 i 75 i if fmod i 2 0 clrscr printf ld n sum 4 下面的程序是求表达式的值 s 1 1 3 1 2 3 5 1 2 3 3 5 7 1 2 3 n 3 5 7 2 n 1 请将程序补充完整 并给出当n 20时 程序的运行结果 按四舍五入保留10位小数 include include includedoublefun intn doubles t inti t 1 0 for i 1 i n i t t i 2 i 1 returns main printf n 12 10lf fun 20 改错题 1 下面的程序是求500以内的所有的素数之和 请修改程序中的错误 使它能得出正确的结果 并给出正确结果 include include includeintprime intn intyes i if n 1 return1 yes 1 for i 2 i sqrt n i if n i 0 yes 0 break return1 main intsum 0 i clrscr for i 2 i 500 i if prime i sum i printf d n sum 2 下面的程序中 函数fun的功能是 根据形参m 计算下面公式的值 T 1 1 2 3 1 3 4 1 m m 1 请改正程序中的错误 并运行改正后的程序 当从键盘输入70时 给出程序运行的正确结果 按四舍五入保留6位小数 include includedoublefun intm doublet 1 0 inti 2 for i 2 i m i t 1 0 i i 1 return main intm clrscr printf n请输入一个整数 scanf d 3 下面的程序中 函数fun的功能是 根据形参m 计算下面公式的值 T 1 1 1 2 1 3 1 m 请改正程序中的错误 并运行改正后的程序 当从键盘输入10时 给出程序运行的正确结果 按四舍五入保留10位小数 include includedoublefun intm doublefac t 0 0 inti 1 j for i 1 i m i fac 1 0 for j 1 j m j fac fac i t 1 0 fac returnt main intm clrscr printf n请输入整数 scanf d 5 下面程序中 函数fun的功能是 计算并输出k以内的最大的10个能被13或17整除的自然数之和 请改正程序中的错误 并运行正确的程序 当从键盘输入500时 给出程序运行的正确结果 include includeintfun intk intm 0 mc 0 j while k 2 mc 10 if k 13 0 main intk clrscr printf n请输入整数 scanf d 6 下列程序的功能是 求出以下分数序列的前30项之和 2 1 3 2 5 3 8 5 13 8 21 13 请改正程序中的错误 并运行修改后程序 给出程序结果 按四舍五入保留6位小数 include includemain longa b c k doubles clrscr s 0 0 a 2 b 1 for k 1 k 30 k s s a b c a a a b b c printf n结果 lf n s 8 下面的程序是计算 s f 30 f 29 f 1 f 0 f 1 f 30 的值 其中函数定义如下 f x x 1 x 2 ifx 1 f x 0ifx 0orx 2 f x x 1 x 2 ifx include includedoublef doublex if x 0 doublefsum intn inti doubles 0 0 y for i n i n i y f 1 0 i s y returny main clrscr printf lf n fsum 30 9 下面的程序是计算如下公式的A15值 A1 1 A2 1 1 A1 A3 1 1 A2 A4 1 1 A3 请改正程序中的错误 并给出程序运行的正确结果 按四舍五入保留10位小数 include includedoublefun intn intA 1 0 inti for i 2 i n i A 1 0 1 A returnA main clrscr printf 12 10lf n fun 15 本章结束 再见 同学们
展开阅读全文
相关资源
相关搜索

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


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

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


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