上课夏6周函数和程序结构_第1页
上课夏6周函数和程序结构_第2页
上课夏6周函数和程序结构_第3页
上课夏6周函数和程序结构_第4页
上课夏6周函数和程序结构_第5页
已阅读5页,还剩43页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第10章函数与程序结构函数的调用方式编译预处理main()函数1函数2……函数m函数1_1函数1_2函数m_1函数m_n……1.程序结构例10-1设计一个常用圆形体体积计算器,采用命令方式输入1、2、3,分别选择计算球体、圆柱体、圆锥体的体积,并输入计算所需相应参数。10.1.1程序解析-计算常用圆形体体积分析:①主函数设计一个功能选择菜单,输入1、2、3进行选择计算3种体积,其他输入结束计算②设计一个控制函数cal(intselect),经它辨别圆形体的类型再调用计算球体、圆柱体、圆锥体体积的函数③设计单独的函数计算不同形体的体积3层结构,5个函数降低程序的编写、调试的复杂度可读性好程序结构main()cal()vol_ball()vol_cylind()vol_cone()例10-1源程序#definePI3.141592654voidcal(intsel);intmain(void){intsel;while(1){printf("1-计算球体体积\n"); printf("2-计算圆柱体积\n"); printf("3-计算圆锥体积\n"); printf("其他-退出程序运行\n"); printf(“请输入计算命令:”); scanf("%d",&sel); if(sel<1||sel>3)break; /*输入非1~3,循环结束*/ else cal(sel); /*输入1~3,调用cal()*/ }return0;}/*体积计算的主控函数*/voidcal(intsel){doublevol_ball(void);doublevol_cylind(void);doublevol_cone(void);switch(sel){ case1: printf("球体积为:%.2f\n",vol_ball()); break;case2: printf("圆柱体积为:%.2f\n",vol_cylind()); break;case3: printf("圆锥体积为:%.2f\n",vol_cone()); break;default:break; }}doublevol_cylind()/*计算圆柱体积V=PI*r*r*h*/{doubler,h;printf("请输入圆柱的底圆半径和高:");scanf("%lf%lf",&r,&h);return(PI*r*r*h);}doublevol_cone()/*计算圆锥体积V=h/3*PI*r*r*/{doubler,h;printf("请输入圆锥的底圆半径和高:");

scanf("%lf%lf",&r,&h);return(PI*r*r*h/3.0);}doublevol_ball()/*计算球体体积V=4/3*PI*r*r*r*/{doubler;printf("请输入球的半径:");scanf("%lf",&r);return(4.0/3.0*PI*r*r*r);}2.函数的调用方式1)顺序调用2)嵌套调用3)递归调用2.函数的调用方式intmain(void){……y=f1(3);……z=f2(3.5,2);

……}doublefunc1(intn){……}doublef2(doublex,inn){……}mainf1

f2mainf1f2顺序调用函数的调用方式intmain(void){……cal(sel);……}voidcal(intsel){ ……vol_ball()……}doublevol_ball(){ ……}maincalvol_ballmaincalvol_ball在函数中调用其它函数,被称为函数嵌套嵌套调用函数的调用方式求n!=1*2*3…*(n-1)*n递归调用result=1;for(result=1,i=1;i<=n;i++)result=result*i;递推法n!=(n-1)!*n(n-1)!=(n-2)!*(n-1)3!=2!*32!=1!*21!=10!=1递归定义n!=n*(n-1)!(n>1)n!=1(n=0,1)函数的调用方式voidmain(){doublefact(intn);printf("%f\n",fact(5));}求n!=1*2*3…*(n-1)*ndoublefact(intn){doubleres;if(n==0||n==1)res=1;elseres=n*fact(n-1);returnres;}递归定义n!=n*(n-1)!(n>1)n!=1(n=0,1)递归调用函数自己调用自己递归出口递归式计算fact(3)3*fact(2)2*fact(1)fact(1)=12*1=23*2=64*6=24printf("%f\n",fact(3));main()fact(3)fact(2)fact(1){....{....{....{....printf(…,fact(3))f=3*fact(2)f=2*fact(1)f=1}return(f)return(f)return(f)}}}同时有4个函数在运行,且都未完成函数的调用方式递归调用函数的调用方式递归调用递归解决问题必须满足如下两个条件1)问题可以递归表达(递归式)2)递归最终能结束

(递归出口)n!=n*(n-1)!nn-1Σi=n+Σii=1i=1例10-5汉诺(Hanoi)塔将64个盘从座A搬到座B(1)一次只能搬一个盘子(2)盘子只能插在A、B、C三个杆中(3)大盘不能压在小盘上

A BC例10-5汉诺(Hanoi)塔难于找到重复的规律?无法用循环模拟hanio(n个盘,A→B)/*C为过渡*/{if(n==1)

直接把盘子A→Belse{hanio(n-1个盘,A→C)

把n号盘A→B hanio(n-1个盘,C→B) }}递归出口递归表达hanio(n个盘,A→B)//C为过渡{if(n==1)直接把盘子A→Belse{hanio(n-1个盘,A→C)

把n号盘A→B hanio(n-1个盘,C→B) }}/*搬动n个盘,从a到b,c为中间过渡*/voidhanio(intn,chara,charb,charc){if(n==1)printf("%c-->%c\n",a,b);else{hanio(n-1,a,c,b);/*从塔a->c,以塔b为过渡*/printf("%c-->%c\n",a,b);hanio(n-1,c,b,a);/*从塔c->b,以塔a为过渡*/}}

源程序

/*搬动n个盘,从a到b,c为中间过渡*/voidhanio(intn,chara,charb,charc){if(n==1)printf("%c-->%c\n",a,b);else{hanio(n-1,a,c,b);printf("%c-->%c\n",a,b);hanio(n-1,c,b,a);}}intmain(void){intn;printf("inputthenumberofdisk:");scanf("%d",&n);printf("thestepsfor%ddiskare:\n",n);hanio(n,'a',‘b',‘c');return0;}对于递归定义的问题我们采用了递归调用编程来解决C语言的函数本身是不能递归定义的。intfunction(….){}P199函数的直接递归调用函数的间接递归调用C编译预处理(p207)

增强C语言的编程功能,改进C语言设计环境,提高编程效率#include<stdio.h>scanf(),printf()#definePI3.1416#开头,无分号,不属于C语言的编程语句。在真正编程之前,做一个预处理现有的C编译器实际上都包含了:预处理、编译和连接C语言的编译预处理功能

文件包含宏定义条件编译1)文件包含(P195)当任务变得复杂,需要:多任务分解=>多人合作,多个文件单个文件太大=>多个文件把包含一部分程序的文件称为文件模块如何将多个文件模块连接成一个完整的可执行程序?只有一个main()函数由main()调用本文件的其它函数

或其它文件模块的函数1)文件包含(P195)格式

#include<需包含的文件名>#include“需包含的文件名”<……>

在系统环境中所指定的路径下查找,“……“先到当前工作夹寻找,若找不到再到系统下寻找作用把指定的文件模块内容插入到程序中#include所在的位置,当程序编译连接时,系统会把所有#include指定的文件拼接生成可执行代码。#include“prog2.c”voidcal(intsel){……}intmain(void){intsel;while(1){scanf("%d",&sel);……cal(sel);}}程序模块prog1.cdoublevol_ball(){ ……}doublevol_cylind(){ ……}doublevol_cone(){……}

程序模块prog2.c编译连接后包含的内容doublevol_ball(){ ……}doublevol_cylind(){……}doublevol_cone(){ ……}voidcal(intsel){……}

intmain(void){intsel;while(1){scanf("%d",&sel);……cal(sel);}}10.1.3文件包含文件包含说明:1)编译预处理命令,以#开头。2)在程序编译时起作用,不是真正的C语句,行尾没有分号。3)“.h”文件与“.c”性质相同,都是C程序文件,“.h”文件突出了头文件(head)的性质。4)被包含文件与其所在的文件,在预编译后就成为了同一个文件(而不是两个文件)。使用工程文件创建一个工程文件intcount=0;main(){

externintfunc2();func2();}intcount;intfunc2(){…count++;}externcount;全局变量只能在一个模块中定义。若其它模块要使用该全局变量,需要通过外部变量声明

文件f1.c

文件f2.cmain(){

externintfunc2();func2();}intcount;intfunc2(){…count++;}全局变量作用范围是整个程序staticintcount;若要限制全局变量在一个程序模块内其作用使用静态全局变量一般全局变量静态全局变量函数的局部变量复合语句内的局部变量

文件名f2.c

文件名f1.c寄存器变量和外部变量(p197)寄存器变量register

int

变量表;寄存器是指CPU内部的数据单元。外部变量extern

变量名表;只起说明作用,不分配存储单元,对应的存储单元在全局变量定义处分配。变量的存储类别:auto,staticexterncount;main(){

func2();}intcount;intfunc2(){…count++;}externintfunc2();外部函数函数能够被程序中的其他程序文件模块调用在其他文件模块中调用该函数前,声明为外部函数extern

函数类型函数名(参数表说明);

文件名f1.c

文件名f2.cintf1(){………}externintf1();intmain(void){………f1();………}内部函数使函数只能在本程序文件模块中被调用static

函数类型函数名(参数表说明);

文件名f1.c

文件名f2.cstaticintf1()无法调用2)宏定义形式1:不带参数的宏定义#define宏名标识符宏定义字符串形式2:带参数的宏定义#define宏名标识符(参数表)

宏定义字符串

#definePI3.1416#defineMAX1000#defineAREA(r)PI*(r)*(r)2)宏定义形式1:不带参数的宏定义#define宏名标识符宏定义字符串编译时,把程序中所有与宏名相同的字符串,用宏定义字符串替代。形式2:带参数的宏定义#define宏名标识符(参数表)宏定义字符串

#definePI3.1416#defineMAX10002)宏定义宏定义可以写在程序中任何位置,它的作用范围从定义书写处到文件尾。可以通过“#undef”强制指定宏的结束范围#defineA"Thisisthefirstmacro"voidf1(){printf("A\n");}#defineB"Thisisthesecondmacro\n"/*A的有效范围*/voidf2(){printf(B);/*B的有效范围*/}#undefBintmain(void){f1();f2();return0;}例10-6宏的作用范围#defineF(x)x-2#defineD(x)x*F(x)intmain(){printf("%d,%d",D(3),D(D(3))); return0;}带参数的宏定义宏定义字符串仅仅是一种机械的替换串如何阅读带宏定义的程序?

先全部替换好,最后再统一计算不可以一边替换一边计算,更不可以人为添加括号#defineF(x)x-2#defineD(x)x*F(x)printf("%d,%d",D(3),D(D(3)));D(3)=>x*F(x) =>x*x-2=>3*3-2=7用D(x)的宏替换,展开参数x用F(x)的宏替换,这里不能加括号最后把x=3代进去计算如何阅读带宏定义的程序?

先全部替换好,最后再统一计算不可以一边替换一边计算,更不可以人为添加括号#defineF(x)x-2#defineD(x)x*F(x)printf("%d,%d",D(3),D(D(3)));D(D(3))=>D(x*F(x))=>D(x*x-2)=>x*x-2*F(x*x-2)=>x*x-2*x*x-2-2 =>3*3-2*3*3-2-2=-13

对D(3)宏展开对F(x)宏展开对D(…)宏展开对F(…)进一步进行宏替换最后把x=3代进去计算10.3.2带参数的宏定义例:#definef(a)a*a*aint main(void)/*水仙花数*/{inti,x,y,z;for(i=1;i<1000;i++){x=i%10;y=i/10%10;z=i/100;if(x*x*x+y*y*y+z*z*z==i) printf(“%d\n”,i);} return0;}#definef(a)(a)*(a)*(a)各位数字的立方和等于它本身的数。例如153的各位数字的立方和是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<stdio.h>#defineM(a,b)(a)>(b)?(a):(b)#defineS(x)(x)*(x)intmain(void){ intx,y; scanf(“%d%d”,&x,&y); x=M(x,y); /*引用宏定义*/ y=S(x); /*引用宏定义*/ printf(“%d%d\n”,x,y); return0;}宏定义使用注意事项#defineS1(r)PI*(r)*(r)#defineS2(r)PI*r*rvoidmain(){floata=1.0,b=2.0;area1=S1(a);are12=S2(a);}area1=PI*(a)*(a);area2=PI*a*a;宏定义使用注意事项#defineS1(r)PI*(r)*(r)#defineS2(r)PI*r*rvoidmain(){floata=1.0,b=2.0;area1=S1(a+b);area2=S2(a+b);}area1=PI*(a+b)*(a+b);area2=PI*a+b*a+b;在行参是表达式时,注意宏展开时可能出现的问题区别()对宏展开的影响宏定义使用注意事项在宏名与带参数的括号之间不应有空格#defineS(r)PI*(r)*(r)voidmain(){floata=1.0;floatarea;area=S(a);}area=(r)PI*(r)*(r)(a);一定要注意严格的宏替换格式带参数的宏定义与带参数的函数是两个不同的概念宏定义使用注意事项①宏定义中的参数只是一种字符替代#defineS2(r)PI*r*rarea2=PI*a+b*a+b;are12=S2(a+b);函数调用时,将实参表达式计算值传递给行参,涉及参数的数据类型,内存分配,实参值的传递以及函数值的返回等

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论