收藏 分销(赏)

第6章函数及预处理.ppt

上传人:仙人****88 文档编号:12560342 上传时间:2025-10-30 格式:PPT 页数:63 大小:347KB 下载积分:10 金币
下载 相关 举报
第6章函数及预处理.ppt_第1页
第1页 / 共63页
第6章函数及预处理.ppt_第2页
第2页 / 共63页


点击查看更多>>
资源描述
Click to edit Master title style,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,*,*,第6章,函数和预处理,6.1,函数的定义,6.2函数的调用,6.,3,变量,的作用域和存储特性,6.,4,内部函数和外部函数,6.,5,预处理命令,6.,6,文件包含,6.,7,条件编译,模块化程序设计思想,模块化程序设计方法:,将一个大问题分解成多个小问题的模块(功能模块,),的设计思想。,功能模块,:求解较小问题的算法和程序,又称作为“,函数,”。,各功能模块可以先单独设计,然后将所有功能模块组合。,6.1 函数,函数,:是组成,C,程序的基本单位,也是,C,程序设计的核心。,C,语言由于采用了函数模块式的结构,语言易于实现结构化程序设计。使程序的层次结构清晰,便于程序的编写、阅读、调试。,6.1,.1 C,中的函数,说明,:,一个,C,程序由一个或多个源程序文件组成。,一个源程序文件由,一个,main,或多个其它函数组成。,所有函数都是平行的,即函数定义时是互相独立的,一个函数并不从属于另一个函数。,C,程序的执行,从,main,函数开始,,调用其他函数后流程回到,main,函数,,在,main,函数中结束,整个程序运行。,6.1,.2,函数的分类,标准函数,即库函数。,它由,C,语言编译系统提供,用户只要在程序头部将包含这些库函数的头文件包含进来,就可以直接使用它们。,用户自定义函数。,即用户自己编写的函数,执行一个特定的任务。,6.1,.3,用户自定义函数,-,定义形式,返回值类型,函数名,(,类型,参数,1,类型,参数,2,),函数体,return,表达式,;,例如,:,int,add(int,a,int,b),int,sum=,a+b,;,return,sum;,返回值类型即函数的类型,如,int,、,float,、,char,等。若函数不提供返回值,则可定义其类型为,:void,函数名又称函数标识符。命名遵循,C,语言标识符的规定,6.1,.3,用户自定义函数分类,无参函数,函数的定义无参数说明,有参函数,定义的参数有一个或一个以上的参数,空函数,当定义的函数既无参数也无执行语句。,空函数被调用时,什么也不做立即返回其调用函数。,6.1,.4,无参函数定义,函数的定义无参数说明,形式:,返回值类型,函数名,(),函数体,函数调用格式:,函数名(),;,输出两行星号*,并在两行星号之间输出“,This is C,Progam,!”,。,void,print_star,(),printf,(*n);,void,print_message,(),printf,(This is,C,Progam,!n,);,void main(),print_star,();,print_message,();,print_star,();,程序运行结果:,*,This is,C,Progam,!,*,本例中定义了三个函数,其中函数,print_star,和,print_message,分别完成输出一行星号和输出一行信息的功能,这两个函数都没有参数。,【,例,6.1】,6.1,.5,函数原型,函数定义在调用函数之后,需要进行函数,声明,-,函数原型。,将,【,例,6.1】,结构,修改如下:,void,print_star,(),;,void,print_message,(),;,void main(),print_star,();,print_message,();,print_star,();,void,print_star,(),printf,(*n);,void,print_message,(),printf,(This is,C,Progam,!n,);,程序运行结果:,*,This is,C,Progam,!,*,函数原型(函数声明),注意,分号,不可省略,一个较为复杂的,C,程序,通常由一个,main,主函数和若干其它函数组成,这些子函数就实现各个模块的功能,在主函数中来调用这些子函数,函数调用时进行参数传递。,6.1,.6,有参函数定义,定义的函数有一个或一个以上的参数,形式:,返回值类型,函数名,(,类型,参数,1,类型,参数,2,),函数体,return,表达式,;,返回值类型与,return,后的,表达式值类型一致。,函数的返回值是通过函数中的,return,语句获得的。,6.1,.7,函数参数,函数参数,:,形参,(,形式参数,):,在定义函数时,定义函数名后面括号中的变量名,实参,(,实际参数,):,在主调函数中调用一个函数,调用函数名后面括号中的参数,(,或表达式,),int Average(int x,int y),int,result;,result=(x+y)/2;,return result;,main(),int a=12;,int b=24;,int ave;,ave=Average(a,b);,printf();,数据传递,执行顺序,实参,形参,6.,2,函数调用,调用函数时,必须提供所有的参数(且必须是已赋值的),提供的参数个数、类型、顺序应与定义时一一对应,(,特例,,printf,和,scanf,是采用变长变量表定义的函数,所以变量的个数不固定。),形式参数,实际参数,函数调用的格式为:,函数名(实参表),;,函数返回值,有返回值时,,放到一个数值表达式中,如:,c=,max(a,b,);,作为另一个函数调用的参数,如:,c=,max(max(a,b),c,);,作为一个数值表达式输出,如:,printf(%dn,max(a,b,);,返回值,=,函数名,(,实参表列,);,【,例,6.2】,计算两个整数的平均数,/*,函数功能:计算平均数,函数入口参数:整型,x,,存储第一个运算数,整型,y,,存储第二个运算数,函数返回值:平均数,*,/,int,Average(,int,x,int,y),int,result;,result=(x+y)/2;,return,result;,例,6.2(,续,)main,函数中调用,Average,函数,main,(),int,a=12;,int,b=24;,int,ave;,ave=Average(a,b);,printf,(,Average of%d and%d is%d.n,a,b,ave,);,int Average(int x,int y),int,result;,result=(x+y)/2;,return result;,main(),int a=12;,int b=24;,int ave;,ave=Average(a,b);,printf();,数据传递,执行顺序,例,6.2,#,include,/*,函数功能:计算平均数,函数入口参数:整型,x,,存储第一个运算数,整型,y,,存储第二个运算数,函数返回值:平均数,*,/,int,Average(,int,x,int,y),int,result;,result=(x+y)/2;,return,result;,main,(),int,a=12;,int,b=24;,int,ave=Average(a,b);,printf,(Average of%d and%d is%d.n,a,b,ave);,当返回值为整型或者函数定义在函数调用前面时,可以省略原型,6.,2.1,函数原型,调用一个函数之前,先要对其,返回值类型,、,函数名,和,参数,进行声明(,declare,),有助于编译器进行类型检查,声明时不要省略参数以及返回值的类型,#,include,int,Average,(,int,x,int,y);,/*,声明,Average(),函数*,/,main,(),int,a=12;,int,b=24;,int,ave=Average(a,b);,printf,(Average of%d and%d is%d.n,a,b,ave);,int,Average(,int,x,int,y),int,result;,result=(x+y)/2;,return,result;,将,【,例,6.2】,结构,修改如下:,main(),a();,a,函数,b();,return;,b,函数,return;,在被调函数中,又调用了函数,-,嵌套调用,6.,2.2,函数的嵌套调用,【,例,6.3】,计算出该日为该年的第几天,输入年月日,计算出该日为该年的第几天。,主控模块,判断闰年,求某月的天数,输 出,输 入,求总天数,图,5-3,程序结构图,程序实现,:,(,1,),判断闰年。,int,leap(int,year),int,lp,;,lp,=(year%4=0,return,lp,;,(,2,)求某月的天数,(,month_days,函数调用,leap,函数),。,int,month_days(int,year,int,month),int,d;,switch(month),case 1:,case 3:,case 5:,case 7:,case 8:,case 10:,case 12:d=31;break;,case 2:d=,leap,(year)?29:28;break;,default:d=30;,return d;,(,3,)求天数和,(,days,函数调用,smonth_days,函数调用,leap,函数),。,int,days(int,year,int,month,int,day),int,i,ds,=0;,for(i=1;i0,例程序:,#include,int,fac(int,n),int,f;,if (n=0),f=1;/*,递归结束条件*,/,else f=n*fac(n-1);,return f;,main(),int,y,n,;,scanf(“%d,”,y=,fac(n,);,printf(“%d,!=%,dn,”,n,y);,分析,:,当程序输入,3,时,y=fac(3),3*fac(2),2*fac(1),1*fac(0),1,例,6.5,汉诺塔游戏,汉诺塔,(Tower of Hanoi),游戏。底座上有三根针,第一根针上放着从大到小,64,个金片。游戏的目标是把所有金片从第一根针通过第二根针移到第三根针上。移动过程中大的金片不能压在小的金片上。,把,n(n1),个金片从第一根针,A,上移到第三根针,C,的问题分解成如下步骤,:,(1),将,n-1,个金片从,A,借助,C,移动到,B,。,(2),将第,n,个金片从,A,移动到,C,。,(3),再将,n-1,个金片从,B,借助,A,移动到,C,。,A,B,C,#include,void,hanoi,(int,n,char a,char b,char c),if,(,n=0,),printf,不处理,n,);,/*0,个金片不处理*,/,if(n=1),printf(%c,-%,cn,a,c,);,/*n=1,时,直接将金片从,a,移动到,c*/,else,hanoi(n-1,a,c,b);,/*,先将,n-1,个金片从,a,经过,c,移动到,b*/,printf(%c,-%,cn,a,c,);,/*,将第,n,个金片从,a,移动到,c*/,hanoi(n-1,b,a,c);,/*,再将,n-1,个金片从,b,经过,a,移动到,c*/,/*,主函数如下:,*/,void,main,(),int,n;,printf(Input,n:);,scanf(%d,&n,);,hanoi,(n,A,B,C,),;,/*n,个金片从第一根针经过第二根针移动到第三根针上*,/,6.3,变量的作用域及存储特性,请看以下程序:,void f1(),printf,(“a=%,dn,”,a);,main(),int,a=5;,f1();,/*,调用函数,f1()*/,printf,(“a=%,dn,”,a);,编译程序会提示出错,:,a Undefined symbol,,为什么,?,6.3.1,变量的作用域,变量的作用域,是指一个变量的,作用范围,。,分为,局部变量,和,全局变量,。,局部变量,局部变量(内部变量),在语句块内或函数体内定义的变量,形参也是局部变量,特点,作用范围:从定义处到本语句块或函数结束。,并列语句块或者函数中各自定义的同名变量互不干扰。,全局变量,全局变量(外部变量),在所有函数之外定义的变量,特点,作用范围:从定义处到文件结束。,使函数之间的数据交换更容易、更方便,也更高效。,但是并不推荐使用,尽量少用,因为谁都可以改写全局变量,所以很难确定是谁改写了它,6.3.2,变量的存储特性,变量的存储特性,:是指数据在内存中存储的方式。,1.,变量按存在时间分,:,静态变量,动态变量,静态存储变量:生存期为程序执行的整个过程,在该过程中占有固定的存储空间,也称永久存储。,动态存储变量:只生存在某一段时间内。,2.,变量属性:数据类型,存储特性,完整的变量定义,:,存储特性,数据类型,变量名,;,例,:,static,int,x,y,;,自动型,auto,静态型,static,寄存器型,register,外部型,extern,变量的存储特性,自动变量(,auto,),“自动”体现在,进入语句块时自动申请内存,退出时自动释放内存,标准定义格式,auto,类型名 变量名,;,动态局部变量,缺省,的存储类型,不初始化时,值是随机,不确定,的,静态变量(,static,),静态变量,在变量类型前面用,static,修饰,标准定义格式,static,int,i;,变量的值可以保存到下次进入函数,使函数具有记忆功能,不初始化时,,值是,0,分析下列程序,写出程序的运行结果,int,f(int,a),int,b=0;,static,int,c=3;,b+;c+;,return(a+b+c,);,main(),int,k;,for(k=0;k3;k+),printf(“%5dn”,f(2);,寄存器变量(,register,),寄存器,CPU,的内部容量很有限、但速度极快的存储器,使用频率比较高的变量声明为,register,,可以使程序更小、,执行速度更快,标准定义格式:,register,int,i;,现代编译器有能力自动把普通变量优化为寄存器变量,并且可以忽略用户的指定,所以一般无需特别声明变量为,register,将局部变量的值放在,CPU,中的寄存器中,这种变量叫“寄存,器变量”,用关键字,register,声明。,外部变量,即全局变量(,extern,),外部,变量,在变量类型前面用,extern,修饰,标准定义格式,extern,int,i;,在定义点之前或在其他文件中引用。,方便函数之间的数据传递;但是并不推荐使用,尽量少用。,6.,4,内部函数和外部函数,C,语言的所有函数都是相对独立的,即不能在一个函数内定义另一个函数。函数之间只有调用关系,没有从属关系。,一般,C,语言的,函数都是全局的,,一个函数可以被其他函数调用,但是,也可以指定函数不能被其他文件中的函数调用,根据函数能否被其它源文件调用,可以将函数分为,内部函数,和,外部函数,。,内部函数的定义:在函数类型标识符前加关键字,static,,则表示此函数为“内部函数”,又称为“静态函数”。,一般形式为:,static,类型标识符 函数名,(,形参表,),内部只能内部函数在定义它的文件中使用,其它文件不能调用。,6.4.1,内部函数,外部函数的定义:在函数类型标识符前加关键字,extern,,则表示此函数为“外部函数”,关键字,extern,可以,省略,。,一般形式为:,extern,类型标识符 函数名,(,形参表,),外部函数可以被其它文件中的函数所调用。若在文件中要调用其它文件中的函数,一般要用,extern,说明所用的函数是外部函数。,6.4.2,外部函数,6.4.3,外部函数的使用,(,1,)用,#include,命令将,file2.cpp,包含到,file1.cpp,中。即在,file1.c,的开头加上下述语句:,#include file2.cpp,(,2,)在工程中使用。先建立一个空工程,然后将,file1.cpp,、,file2.cpp,加入到该工程。,6.,5,编译,预处理命令,编译预处理是在编译前由编译系统中的预处理程序对源程序的预处理命令进行加工。,源程序中的预处理命令均以“,#”,开头,结束不加分号,以区别源程序中的语句,它们可以写在程序中的任何位置,作用域是自出现点到源程序的末尾。,预处理命令包括执行宏定义,(,宏替换,),、包含文件和条件编译。,合理地使用预处命令能编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。,6.5.1,无参宏定义,定义形式:,#define,宏名 串,(,宏体,),如,:#define PI 3.14159,宏定义的作用,宏定义后,该程序中宏名就代表了该字符串。,说明,#,undef,终止宏定义的作用域:,#,undef,PI,宏定义的嵌套使用,#define R 3.0,#define PI 3.1415926,#define L 2*PI*R /*,宏体是表达式*,/,#define S PI*R*R,main(),printf,(,“,L=%,fnS,=%fn,”,,L,,,S),;,程序运行结果如下:,L=18.849556,S=28.274333,双引号内的与宏同名的字母不作宏展开,原样输出。,带参数的宏定义的一般形式:,#define,宏名,(,参数表)字符串,如:,#define S(a,b)a*b,带实参的宏名展开时,宏名被宏体替换,宏体中的形参按从左到右的顺序被实参替换。,例如,:area=S(3,2);,赋值语句展开为:,area=3*2,;,6.5.2,带参宏定义,引用宏只占编译时间,不占运行时间。,引用宏没有返回值。,宏替换的形参无类型。,实参为表达式时:函数调用是,先计算,出实参的值,再,将值,传递,给形参;,宏,的引用是用表达式,替换,形参。,例如:,定义:,#define S(,a,b,)a*b,引用:,S(a+c,b+c,),展开:,a+c,*,b+c,6.5.3,宏定义与函数的区别,6.6,文件包含(,#include,),一个源文件可以将另一个源文件的全部内容包含进来。,#include,命令有两种格式:,(1),#include,(2),#include “,文件名”,编写输出一行星号(*)的函数,print_star,(),。,要求将,print_star,(),函数,和,main(),函数分别放在不同的文件中。,【,例,6.6】,#include file2.cpp,main(),extern void,print_star,();,print_star,();,文件,file1.cpp,中,main,函数要调用,文件,file2.cpp,中的外部,函数,print_star,(),1,),file1.cpp,文件,#include,stdio.h,“,/*,输出一行*的函数,*/,void,print_star,(),printf,(“*n);,2,),file2.cpp,文件,6.7,条件编译,形式一:,#if,常量表达式,程序段,#,endif,功能:,常量表达式非,0,时,程序段被编译。否则程序段不被编译。,形式二:,#if,常量表达式,程序段,#else,程序段,#,endif,功能:,常量表达式为非,0,时,程序段,1,被编译。否则,编译程序段,2,一般源程序的所有内容都参加编译,但有时根据需要,对其中的一部分内容只有当满足一定条件时才进行编译,这就是所谓的“条件编译”。条件编译有以下几种形式。,形式三:,#,ifdef,标识符,程序段,1,#else,程序段,2,#,endif,功能:,如果标识符已被,#define,命令定义过,则对程序段,1,进行编译;否则对程序段,2,进行编译。,模块化程序设计方法,功能分解,自顶向下、逐步求精的过程,模块分解的原则,保证模块的相对独立性,高聚合、低耦合,模块的实现细节对外不可见,外部:关心做什么,内部:关心怎么做,设计好模块接口,接口是指罗列出一个模块的所有的与外部打交道的变量等,定义好后不要轻易改动,在模块开头(文件的开头)进行函数声明,模块化程序设计方法,什么时候需要模块化?,某一功能,如果重复实现,3,遍以上,即应考虑模块化,将它写成通用函数,并向小组成员发布,要尽可能复用其它人的现成模块。,函数设计的原则,函数的,功能要单一,,不要设计多用途的函数,函数的,规模要小,,尽量控制在,50,行代码以内,参数和返回值的规则,参数要书写完整,不要省略,对函数的入口参数进行有效性检查,没有参数和返回值时,用,void,填充,每个函数只有一个入口和一个出口,尽量不使用全局变量,尽量少用静态局部变量,以避免使函数具有“记忆”功能,模块和链接,1,将一个程序分解成若干个模块,分别放在几个源文件中,,,形成一个项目文件,,模块之间通过互相调用函数联系起来。,2,然后,,对每一个源文件,(,.c/.,cpp,),分别,单独进行编译,,,再,将它们的目标代码(,.,obj,),连同标准函数库中的函数,链接,在一起,形成可执行文件(,.exe,)。,3,优点:,当一个文件的代码被修改后,不必对所有程序重新编译,从而节省了程序的编译时间。,使程序更宜于维护,给多个程序员共同编制一个大型项目的代码提供了方便手段。,小结,函数的定义、调用,变量的作用域、存储类别,自动变量 (,auto,),外部变量 (,extern,),静态变量 (,static,),寄存器变量(,register,),模块化程序设计、调试方法,
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 教育专区 > 小学其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服