《chap10_函数与程序结构-精品文档资料整理.ppt》由会员分享,可在线阅读,更多相关《chap10_函数与程序结构-精品文档资料整理.ppt(60页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、Chap 10 函数与程序结构函数与程序结构10.1 函数的组织函数的组织10.2 递归函数递归函数10.3 宏定义宏定义10.4 编译预处理编译预处理本章要点本章要点n怎样把多个函数组织起来?怎样把多个函数组织起来?n怎样用结构化程序设计的思想解决问题?怎样用结构化程序设计的思想解决问题?n怎样用函数嵌套求解复杂的问题?怎样用函数嵌套求解复杂的问题?n怎样用函数递归解决问题?怎样用函数递归解决问题?n如何使用宏?如何使用宏?使用结构化程序设计方法解决复杂的问题使用结构化程序设计方法解决复杂的问题把大问题分解成若干小问题,小问题再进一步分解成把大问题分解成若干小问题,小问题再进一步分解成若干更
2、小的问题若干更小的问题写程序时,用写程序时,用main()解决整个问题,它调用解决小问解决整个问题,它调用解决小问题的函数题的函数这些函数又进一步调用解决更小问题的函数,从而形这些函数又进一步调用解决更小问题的函数,从而形成函数的嵌套调用成函数的嵌套调用10.1 函数的组织函数的组织main()函数函数1函数函数2函数函数m函数函数1_1函数函数1_2函数函数m_1函数函数m_n程序结构程序结构例例10-1 设计一个常用圆形体体积计算器,采用设计一个常用圆形体体积计算器,采用命令方式输入命令方式输入1、2、3,分别选择计算球体、,分别选择计算球体、圆柱体、圆锥体的体积,并输入计算所需相圆柱体、
3、圆锥体的体积,并输入计算所需相应参数。应参数。分析:分析:输入输入1、2、3选择计算选择计算3种体积,其他输入结束计种体积,其他输入结束计算算设设计计一一个个控控制制函函数数cal(),经经它它辨辨别别圆圆形形体体的的类类型型再调用计算球体、圆柱体、圆锥体体积的函数再调用计算球体、圆柱体、圆锥体体积的函数设计单独的函数计算不同圆形体的体积设计单独的函数计算不同圆形体的体积10.1.1 程序解析程序解析-计算常用圆形体体积计算常用圆形体体积3层结构,层结构,5个函数个函数降低程序的构思、编写、调试的复杂度降低程序的构思、编写、调试的复杂度可读性好可读性好程序结构程序结构main()cal()vo
4、l_ball()vol_cylind()vol_cone()例例10-1源程序源程序#define PI 3.141592654void cal(int sel);int main(void)int sel;while(1)printf(1-计算球体体积计算球体体积n);printf(2-计算圆柱体积计算圆柱体积n);printf(3-计算圆锥体积计算圆锥体积n);printf(其他其他-退出程序运行退出程序运行n);printf(“请输入计算命令:请输入计算命令:”);scanf(%d,&sel);if(sel 3)break;/*输入非输入非13,循环结束,循环结束 */else cal(
5、sel);/*输入输入13,调用,调用cal()*/return 0;/*常用圆形体体积计算器的主控函数常用圆形体体积计算器的主控函数 */void cal(int sel)double vol_ball(void);double vol_cylind(void);double vol_cone(void);switch(sel)case 1:printf(球体积为:球体积为:%.2fn,vol_ball();break;case 2:printf(圆柱体积为:圆柱体积为:%.2fn,vol_cylind();break;case 3:printf(圆锥体积为:圆锥体积为:%.2fn,vol_
6、cone();break;/*计算球体体积计算球体体积 V=4/3*PI*r*r*r*/double vol_ball()double r;printf(请输入球的半径:请输入球的半径:);scanf(%lf,&r);return(4.0/3.0*PI*r*r*r);/*计算圆柱体积计算圆柱体积 V=PI*r*r*h */double vol_cylind()double r,h;printf(请输入圆柱的底圆半径和高:请输入圆柱的底圆半径和高:);scanf(%lf%lf,&r,&h);return(PI*r*r*h);/*计算圆锥体积计算圆锥体积 V=h/3*PI*r*r */double
7、 vol_cone()double r,h;printf(请输入圆锥的底圆半径和高:请输入圆锥的底圆半径和高:);scanf(%lf%lf,&r,&h);return(PI*r*r*h/3.0);10.1.2 函数的嵌套调用函数的嵌套调用n顺序调用顺序调用int main(void)y=fact(3);z=mypow(3.5,2);double fact(int n)double mypow(double x,in n)mainfactmypowmainfactmypow函数的嵌套调用函数的嵌套调用n嵌套调用嵌套调用int main(void)cal(sel);void cal(int sel
8、)vol_ball()double vol_ball()maincalvol_ballmaincalvol_ball例例9-1 分析分析int main(void)cal(sel);void cal(int sel)vol_ball();vol_cylind();vol_cone();double vol_ball()double vol_cylind()double vol_cone()main()cal()vol_ball()vol_cylind()vol_cone()函数的嵌套调用函数的嵌套调用在一个函数中再调用其它函数的情况称为函在一个函数中再调用其它函数的情况称为函数的数的嵌套调用嵌
9、套调用。如果函数如果函数A调用函数调用函数B,函数函数B再调用函数再调用函数C,一个调用一个地嵌套下去,构成了函数的嵌一个调用一个地嵌套下去,构成了函数的嵌套调用。套调用。具有嵌套调用函数的程序,需要分别定义多具有嵌套调用函数的程序,需要分别定义多个不同的函数体,每个函数体完成不同的功个不同的函数体,每个函数体完成不同的功能,它们合起来解决复杂的问题。能,它们合起来解决复杂的问题。10.1.3 文件包含文件包含n程序文件模块程序文件模块为为了了避避免免一一个个文文件件过过长长,可可以以把把程程序序分分别别保保存存为为几个文件。几个文件。一一个个大大程程序序会会由由几几个个文文件件组组成成,每每
10、一一个个文文件件又又可可能包含若干个函数。能包含若干个函数。保存有一部分程序的文件称为保存有一部分程序的文件称为程序文件模块程序文件模块。程序文件函数程序文件函数大程序若干程序文件模块大程序若干程序文件模块各程序文件模块分别编译,再连接各程序文件模块分别编译,再连接整个程序只允许有一个整个程序只允许有一个main()函数函数n问题:如何把若干程序文件模块连接成一问题:如何把若干程序文件模块连接成一个完整的可执行程序?个完整的可执行程序?当一个语言程序由多个文件模块组成时,整当一个语言程序由多个文件模块组成时,整个程序只允许有一个个程序只允许有一个main()函数。函数。为了能调用写在其它文件模
11、块中的函数,文件为了能调用写在其它文件模块中的函数,文件包含是一个有效的解决方法。包含是一个有效的解决方法。文件包含文件包含n格式格式#include#include“需包含的文件名需包含的文件名”n作用作用把把指指定定的的文文件件模模块块内内容容插插入入到到#include 所所在在的的位位置置,当当 程程 序序 编编 译译 连连 接接 时时,系系 统统 会会 把把 所所 有有#include 指定的文件拼接生成可执行代码。指定的文件拼接生成可执行代码。n注意注意编译预处理命令,以编译预处理命令,以#开头。开头。在在程程序序编编译译时时起起作作用用,不不是是真真正正的的C语语句句,行行尾尾没
12、有分号。没有分号。文件包含文件包含将例将例10-1的的5个函数分别存储在个函数分别存储在2个个.C文件上,文件上,要求通过文件包含把它们联结起来。要求通过文件包含把它们联结起来。例例10-2nctype.h 字符处理字符处理nmath.h 与数学处理函数有关的说明与定义与数学处理函数有关的说明与定义nstdio.h 输入输出函数中使用的有关说明和定义输入输出函数中使用的有关说明和定义nstring.h 字符串函数的有关说明和定义字符串函数的有关说明和定义nstddef.h 定义某些常用内容定义某些常用内容nstdlib.h 杂项说明杂项说明ntime.h 支持系统时间函数支持系统时间函数常用标
13、准头文件常用标准头文件10.1.4 全局变量与程序文件模块全局变量与程序文件模块 n局部变量局部变量作用范围:函数(复合语句)内部作用范围:函数(复合语句)内部生命周期:从生命周期:从函数函数调用开始函数调用开始函数调用结束调用结束n全局变量全局变量作用范围:从定义处到源文件结束作用范围:从定义处到源文件结束生命周期:生命周期:从从程序程序执行开始程序运行结束执行开始程序运行结束n静态局部变量静态局部变量作用范围:局部变量作用范围:局部变量生命周期:全局变量生命周期:全局变量外部变量(外部变量(extern)n在某个程序文件模块中定义了全局变量在某个程序文件模块中定义了全局变量n该该全全局局变
14、变量量可可以以在在整整个个程程序序的的所所有有文文件件模模块块中起作用中起作用n在在其其他他模模块块中中如如果果要要使使用用该该全全局局变变量量,必必须须将它声明为外部变量将它声明为外部变量说明这是一个在其他模块中定义的全局变量说明这是一个在其他模块中定义的全局变量int x;void main()文件名文件名 file1.cextern x;/*使用使用file1.c中的全中的全局变量局变量 x */f1()文件名文件名 file2.c扩大全局变量扩大全局变量的作用域的作用域static int x;void main()使全局变量只限于本文件引用,而不能被使全局变量只限于本文件引用,而不能
15、被其他文件引用其他文件引用 文件名文件名 file1.cextern x;/*使用使用file1.c中的全中的全局变量局变量 x */int f1()文件名文件名 file2.c无法引用无法引用静态全局变量静态全局变量n普通全局变量普通全局变量 整个程序整个程序n静态全局变量静态全局变量 文件模块文件模块n函数的局部变量函数的局部变量 函数函数n复合语句的局部变量复合语句的局部变量 复合语句复合语句10.1.5 寄存器变量和外部变量寄存器变量和外部变量n寄存器变量寄存器变量register int 变量表变量表;n外部变量外部变量extern 变量名表变量名表;只起说明作用,不分配存储单元,对
16、应的存储只起说明作用,不分配存储单元,对应的存储单元在全局变量定义处分配。单元在全局变量定义处分配。10.1.6 函数与程序文件模块函数与程序文件模块n外部函数外部函数函数能够被程序中的其他程序文件模块调用函数能够被程序中的其他程序文件模块调用在其他文件模块中调用该函数前,声明为外部函数在其他文件模块中调用该函数前,声明为外部函数extern 函数类型函数类型 函数名函数名(参数表说明参数表说明);extern int f1();int main(void)f1();文件名文件名 file1.cint f1()文件名文件名 file2.c调用另一模块调用另一模块中的函数中的函数extern i
17、nt f1();int main(void)f1();static int f1()n内部函数内部函数使函数只能在本程序文件模块中被调用使函数只能在本程序文件模块中被调用static 函数类型函数类型 函数名函数名(参数表说明参数表说明);文件名文件名 file1.c 文件名文件名 file2.c无法调用无法调用10.2 递归函数递归函数10.2.1 程序解析程序解析10.2.2 递归函数基本概念递归函数基本概念10.2.3 递归程序设计递归程序设计10.2.1 程序解析程序解析例例10-3 用递归函数求用递归函数求n!。#include double fact(int n);int main
18、(void)int n;scanf(%d,&n);printf(%f,fact(n);return 0;double fact(int n)/*函数定义函数定义 */double result;if(n=1|n=0)/*递归出口递归出口 */result=1;else result=n*fact(n-1);return result;10.2.2 递归函数基本概念递归函数基本概念递推法与递归法求阶乘递推法与递归法求阶乘n递推法递推法n!=1*2*3*.*nfor(result=1,i=1;i 1)n!=1 (n=0,1)递归函数递归函数 fact(n)递归式递归式递归出口递归出口例例9-3分析
19、分析求求n!递归定义递归定义n!=n*(n-1)!(n 1)n!=1 (n=0,1)#include double fact(int n);int main(void)int n;scanf(%d,&n);printf(%f,fact(n);return 0;double fact(int n)double result;if(n=1|n=0)result=1;else result=n*fact(n-1);return result;fact(n)=n*fact(n-1);main()fact(3)fact(2)fact(1).printf(fact(3)f=3*fact(2)f=2*fac
20、t(1)f=1 return(f)return(f)return(f)递归函数递归函数 fact(n)的实现过程的实现过程fact(3)=3*fact(2)2*fact(1)fact(1)12*1=23*2=6同时有同时有4个函数在运个函数在运行,且都未完成行,且都未完成例例10-4 写输出结果写输出结果#include long fib(int g)switch(g)case 0:return(0);case 1:case 2:return(2);printf(g=%d,g);return(fib(g-1)+fib(g-2);void main()long k;k=fib(4);printf
21、(k=%ldn,k);fib(g)=0 g=0fib(g)=2 g=1,2fib(g)=fib(g-1)+fib(g-2)g=3g=4,g=3,k=6如何求如何求Fibonacci数列数列?递归式递归式递归出口递归出口10.2.3 递归程序设计递归程序设计用递归实现的问题,满足两个条件:用递归实现的问题,满足两个条件:n问题可以逐步简化成自身较简单的形式(问题可以逐步简化成自身较简单的形式(递归式递归式)n!=n*(n-1)!n n-1i=n+i i=1 i=1n递归最终能结束递归最终能结束(递归出口递归出口)两个条件缺一不可两个条件缺一不可解决递归问题的两个着眼点解决递归问题的两个着眼点举例
22、:举例:n题目:有题目:有5个人坐在一起,问第五个人多少个人坐在一起,问第五个人多少岁?他说比第岁?他说比第4个人大个人大2岁。问第岁。问第4个人岁数,个人岁数,他说比第他说比第3个人大个人大2岁。问第三个人,又说岁。问第三个人,又说比第比第2人大两岁。问第人大两岁。问第2个人,说比第一个个人,说比第一个人大两岁。最后人大两岁。最后 问第一个人,他说是问第一个人,他说是10岁。岁。请问第五个人多大?请问第五个人多大?n程序分析:利用递归的方法,递归分为回程序分析:利用递归的方法,递归分为回推和递推两个阶段。要想知道第五个人岁推和递推两个阶段。要想知道第五个人岁数,需知道第四人的岁数,依次类推,
23、推数,需知道第四人的岁数,依次类推,推到第一人(到第一人(10岁),再往回推。岁),再往回推。#includeint main(void)int age(int n);printf(%dn,age(5);int age(int n)int c;if(n=1)c=10;else c=age(n-1)+2;return(c);例例10-5 汉诺汉诺(Hanoi)塔塔 将将64 个盘从座个盘从座A搬到座搬到座B(1)一次只能搬一个盘子一次只能搬一个盘子(2)盘子只能插在盘子只能插在A、B、C三个杆中三个杆中(3)大盘不能压在小盘上大盘不能压在小盘上 A B C分析分析 A B C分析分析 A B C
24、 A B Cnn-1分析分析 A B C A B Cnn-1算法算法hanio(n个盘,个盘,AB)/C为过渡为过渡 if(n=1)直接把盘子直接把盘子AB else hanio(n-1个盘,个盘,AC)/B为过渡为过渡 把把n号盘号盘 AB hanio(n-1个盘,个盘,CB)/A为过渡为过渡 A B Cn-1函数函数/*搬动搬动n个盘,从个盘,从a到到b,c为中间过渡为中间过渡 */void hanio(int n,char a,char b,char c)if(n=1)printf(%c-%cn,a,b);else hanio(n-1,a,c,b);printf(%c-%cn,a,b);
25、hanio(n-1,c,b,a);hanio(n个盘,个盘,AB)/C为过渡为过渡 if(n=1)直接把盘子直接把盘子AB else hanio(n-1个盘个盘,AC)把把n号盘号盘 AB hanio(n-1个盘个盘,CB)源程序源程序/*搬动搬动n个盘,从个盘,从a到到b,c为中间过渡为中间过渡 */void hanio(int n,char a,char b,char c)if(n=1)printf(%c-%cn,a,b);else hanio(n-1,a,c,b);printf(%c-%cn,a,b);hanio(n-1,c,b,a);int main(void)int n;printf
26、(input the number of disk:);scanf(%d,&n);printf(the steps for%d disk are:n,n);hanio(n,a,b,c);return 0;练习练习10-1n用递归方法编写斐波那契函数。函数类型用递归方法编写斐波那契函数。函数类型是整型。是整型。nf(n)=f(n-2)+f(n-1)n1,其中其中f(0)=0,f(1)=1#include long func(long n)if(n=0|n=1)return n;else return func(n-1)+func(n-2);int main(void)long n;printf(
27、please input n:);scanf(%ld,&n);printf(the result is%ld,func(n);return 0;10.3 宏定义宏定义#define 宏名标识符宏名标识符 宏定义字符串宏定义字符串编译时,把程序中所有与宏名相同的字符串,用宏定义字编译时,把程序中所有与宏名相同的字符串,用宏定义字符串替代符串替代#define PI 3.14#define arr_size 4说明说明:宏名一般用大写字母,以与变量名区别宏名一般用大写字母,以与变量名区别宏定义不是语句,后面不得跟分号宏定义不是语句,后面不得跟分号宏定义可以嵌套使用宏定义可以嵌套使用#define
28、PI 3.14#define S 2*PI*PI多用于符号常量多用于符号常量n宏定义可以写在程序中任何位置,它的作用范宏定义可以写在程序中任何位置,它的作用范围从定义书写处到文件尾。围从定义书写处到文件尾。n可以通过可以通过“#undef”强制指定宏的结束范围。强制指定宏的结束范围。10.3.1 宏基本定义宏基本定义#define A “This is the first macro”void f1()printf(“An”);#define B “This is the second macro”A 的有效范围的有效范围void f2()printf(B);B 的有效范围的有效范围#unde
29、f Bint main(void)f1();f2();return 0;例例10-6 宏的作用范围宏的作用范围10.3.2 带参数的宏定义带参数的宏定义例:例:#define f(a)a*a*a int main(void)/*水仙花数水仙花数 */int i,x,y,z;for(i=1;i1000;i+)x=i%10;y=i/10%10;z=i/100;if (x*x*x+y*y*y+z*z*z=i)printf(“%dn”,i);return 0;#define f(a)(a)*(a)*(a)各位数字的立方和等于它本各位数字的立方和等于它本身的数。例如身的数。例如153的各位数的各位数字的
30、立方和是字的立方和是13+53+33=153=x+y*x+y*x+y(f(x)+f(y)+f(z)=i)f(x+y)=(x+y)3?带参数的宏定义带参数的宏定义实现简单的函数功能实现简单的函数功能例例10-7 简单的带参数的宏定义。简单的带参数的宏定义。#include#define MAX(a,b)(a)(b)?(a):(b)#define SQR(x)(x)*(x)int main(void)int x,y;scanf(“%d%d”,&x,&y);x=MAX(x,y);/*引用宏定义引用宏定义*/y=SQR(x);/*引用宏定义引用宏定义*/printf(“%d%dn”,x,y);retu
31、rn 0;#define f(a,b,t)t=a;a=b;b=t;int main()int x,y,t;scanf(“%d%d”,&x,&y);f(x,y,t)printf(“%d%dn”,x,y);return 0;t=x;x=y;y=t;编译时被替换编译时被替换带参数的宏定义不是函数,宏与函数是两种不同的概念带参数的宏定义不是函数,宏与函数是两种不同的概念 宏可以实现简单的函数功能宏可以实现简单的函数功能示例示例 用宏实现两个变量值的交换用宏实现两个变量值的交换与函数的区别在哪里与函数的区别在哪里?#define F(x)x-2#define D(x)x*F(x)int main()pr
32、intf(%d,%d,D(3),D(D(3);return 0;带宏定义的程序输出带宏定义的程序输出n阅读带宏定义的程序,先全部替换好,最后再统一计算阅读带宏定义的程序,先全部替换好,最后再统一计算n不可一边替换一边计算,更不可以人为添加括号不可一边替换一边计算,更不可以人为添加括号D(3)=x*F(x)先用先用x替换展开替换展开 =x*x-2 进一步对进一步对F(x)展开,这里不能加括号展开,这里不能加括号 =3*3-2=7 最后把最后把x=3代进去计算代进去计算D(D(3)=D(x*x-2)先对先对D(3)用用x替换展开,替换展开,=x*x-2*F(x*x-2)拿展开后的参数对拿展开后的参数对D进一步进行宏替换进一步进行宏替换 =x*x-2*x*x-2-2 拿展开后的参数对拿展开后的参数对F进一步进行宏替换进一步进行宏替换 =3*3-2*3*3-2-2=-13最后把最后把x=3代进去计算代进去计算运行结果:运行结果:7 -13结果分析结果分析宏定义应用示例宏定义应用示例n定义宏定义宏LOWCASE,判断字符,判断字符c是否为小写字母。是否为小写字母。#define LOWCASE(c)(c)=a)&(c)=0)&(c)0)3、用递归的方法实现对一个整数逆序输出。、用递归的方法实现对一个整数逆序输出。