为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

C语言程序设计教程 教学课件 作者 李丽娟 第6章函数与宏定义

2020-01-13 49页 ppt 710KB 2阅读

用户头像 个人认证

希望

暂无简介

举报
C语言程序设计教程 教学课件 作者 李丽娟 第6章函数与宏定义C程序设计基础教程第六章函数与宏定义**/49第六章函数与宏定义§6.1函数概念§6.2变量作用域和存储类型§6.3内部函数与外部函数§6.4递归函数设计和调用§6.6综合范例C程序设计基础教程第六章函数与宏定义**/49§6.1函数概念C语言允许把问题设计成一个一个的模块,程序通过调用模块功能来解决问题。这些模块通常都是通过函数来实现的,又可称其为函数模块。C语言中,函数可分为两类:一类是由系统定义的标准函数,又称为库函数,其函数声明一般是放在系统的include目...
C语言程序设计教程 教学课件 作者 李丽娟 第6章函数与宏定义
C程序设计基础教程第六章函数与宏定义**/49第六章函数与宏定义§6.1函数概念§6.2变量作用域和存储类型§6.3内部函数与外部函数§6.4递归函数设计和调用§6.6综合范例C程序设计基础教程第六章函数与宏定义**/49§6.1函数概念C语言允许把问题设计成一个一个的模块,程序通过调用模块功能来解决问题。这些模块通常都是通过函数来实现的,又可称其为函数模块。C语言中,函数可分为两类:一类是由系统定义的函数,又称为库函数,其函数声明一般是放在系统的include目录下以.h为后缀的头文件中,如在程序中要用到某个库函数,必须在调用该函数之前用#include<头文件名>命令将库函数信息包含到本程序中。另一类函数是自定义函数,两种形式:第一种:函数声明、函数调用、函数定义。第二种:函数定义、函数调用。C程序设计基础教程第六章函数与宏定义**/49§6.1.1函数定义函数定义的一般形式可以有两种。形式一:[存储类型符][返回值类型符]函数名([形参说明]){函数语句体}形式二:[存储类型符][返回值类型型符]函数名([形参表])形参说明;{函数语句体}C程序设计基础教程第六章函数与宏定义**/49说明:1.[存储类型符]指的是函数的作用范围,它只有两种形式:static和extern。static说明函数只能作用于其所在的源文件,用static说明的函数又称为内部函数。extern说明函数可被其它源文件中的函数调用,用extern说明的函数,又称为外部函数。缺省情况为extern。2.[返回值类型符]指的是函数体语句执行完成后,函数返回的值的类型,如int,float,char等等,若函数无返回值,则用空类型void来定义函数的返回值。缺省情况为int型。C程序设计基础教程第六章函数与宏定义**/493.函数名由任何合法的标识符构成。建议将函数名的命名与函数内容有一定关系。4.在第一种函数定义的形式中,[形参说明表]是一系列用逗号分开的每个形参变量说明。如:intx,inty,intz这表示形参变量有三个:x,y,z。它们的类型都是int型。在第二种函数定义的形式中,[形参表]是一系列用逗号分开的形参变量。如:x,y,z5.函数语句体是放在一对花括号{}中,由局部数据类型描述和功能实现两部分组成。C程序设计基础教程第六章函数与宏定义**/496.函数返回语句的形式有以下两种:①函数无返回值的情况:return;②函数有返回值的情况:return(表达式的值);在第②种情况下要注意“表达式的值”的类型必须与函数返回值的类型相一致。例如:求两个任意整数的绝对值的和,用函数abs_sum()实现。/*直接调用库函数来计算m和n的绝对值*/intabs_sum(intm,intn){return(abs(m)+abs(n));}/*函数abs()是在头文件math.h中声明的*/C程序设计基础教程第六章函数与宏定义**/49函数定义如下:intabs_sum(intm,intn){if(m<0)m=-m;if(n<0)n=-n;return(m+n);}§6.1.2函数声明和调用一.函数的声明函数声明的一般形式:[存储类型符][返回值类型符]函数名([形参说明表]);如:intabs-sun(intm,intn);C程序设计基础教程第六章函数与宏定义**/49二.函数调用函数调用是通过函数调用语句来实现的,分两种形式:①无返回值的情况:函数名([实参表]);②有返回值的情况:变量名=函数名([实参表]);该变量名的类型必须与函数的返回值类型相同。函数调用时都会去执行函数语句中的内容,函数执行完毕后,回到函数的调用处,继续执行下面的语句。C程序设计基础教程第六章函数与宏定义**/49§6.1.3函数的传值方式函数的传值方式:采用实参表将每一个实参的值相应地传递给每一个形参变量,形参变量在接收到实参表传过来的值时,会在内存临时开辟新的空间,以保留形参变量的值,当函数执行完毕时,这些临时开辟的内存空间会被释放,并且形参的值在函数中不论是否发生变化,都不会影响到实参变量的值的变化,这就是函数的传值方式。自定义函数在程序中的使用顺序有两种形式:①先进行函数声明,再进行函数调用,函数定义放在函数调用之后。函数声明在函数调用之前。②函数定义放在函数调用之前。C程序设计基础教程第六章函数与宏定义**/49【例6-1】编程序,通过调用函数abs-sum(),求任意两个整数的绝对值的和。/*exam6_1.c调用函数求两整数绝对值的和*/#include<stdio.h>intabs_sum(intm,intn);main(){ intx,y,z; scanf("%d%d",&x,&y); z=abs_sum(x,y); printf("sumis%d",z);}intabs_sum(intm,intn){ if(m<0) m=-m; if(n<0) n=-n; returnm+n;}程序运行结果:712sumis19C程序设计基础教程第六章函数与宏定义**/49用传值方式调用函数时,实参也可以是函数调用语句【例6-2】求任意三个数的绝对值的和。/*exam6_2.c调用函数求三个整数绝对值的和*/#include<stdio.h>intabs_sum(intm,intn);main(){ intx,y,z,sum; scanf("%d%d%d",&x,&y,&z); sum=abs_sum(abs_sum(x,y),z); printf("sumis%d",sum);}intabs_sum(intm,intn){ if(m<0) m=-m; if(n<0) n=-n; returnm+n;}程序运行结果:7125sumis24C程序设计基础教程第六章函数与宏定义**/49注意:对于有返回值的函数,调用时若没有把它赋给某个变量,仍然是可以的,只是函数的返回值有可能会被丢失。【例6-3】求任意两数的乘积。自定义一个函数mul(),用于求两数的乘积,程序:/*exam6_3.c求两个数的乘积*/#include<stdio.h>floatmul(floata,floatb);main(){ floatx,y,z; scanf("%f%f",&x,&y); z=mul(x,y);/*①*/ x=x+10; y=y-10; mul(x,y);/*②*/C程序设计基础教程第六章函数与宏定义**/49 x=x*2; y=y*2; printf("z=%f,mul(%f,%f)=%f\n",z,x,y,mul(x,y));/*③* /}floatmul(floata,floatb){ returna*b;}程序运行结果:56z=30.000000,mul(30.000000,-8.000000)=-240.000000C程序设计基础教程第六章函数与宏定义**/49程序说明:注释①处调用函数后的返回值赋给变量z。注释②处调用函数后的返回值没有赋给任何变量,函数的返回值被丢失。注释③处调用函数后的返回值成为了printf()函数的参数。C程序设计基础教程第六章函数与宏定义**/49§6.2变量作用域和存储类型一.变量的作用域变量的作用域:指的是变量的有效范围,针对变量不同的作用域,可把变量分为局部变量和全局变量。局部变量:在函数内部或某个控制块的内部定义的变量为局部变量,局部变量的有效范围只限于本函数内部,退出函数,该变量自动失效。全局变量:在函数外面定义的变量称为全局变量,全局变量的作用域是从该变量定义的位置开始,直到源文件结束。在同一文件中的所有函数都可以引用全局变量。C程序设计基础教程第六章函数与宏定义**/49局部变量和全局变量的作用域如图所示:C程序设计基础教程第六章函数与宏定义**/49【例6-4】变量作用域应用举例,阅读下面的程序,注意区分局部变量和全局变量的作用域。/*exam6_4.c变量作用域举例*/#include<stdio.h>voida(void);voidb(void);voidc(void);intx=1;main(){ intx=5; printf("localxinouterscopeofmainis%d\n",x);C程序设计基础教程第六章函数与宏定义**/49 { intx=7; printf("localxininnerscopeofmainis%d\n",x); } printf("localxinouterscopeofmainis%d\n",x); a(); b(); c(); a(); b(); c();前三次输出结果:localxinouterscopeofmainis5localxininnerscopeofmainis7localxinouterscopeofmainis5C程序设计基础教程第六章函数与宏定义**/49 printf("localxinmainis%d\n",x); getchar(); return0;}voida(void){ intx=25; printf("\nlocalxinais%dafterenteringa\n",x); ++x; printf("localxinais%dbeforeexitinga\n",x);}C程序设计基础教程第六章函数与宏定义**/49voidb(void){ staticintx=50; printf("\nlocalstaticxis%donenteringb\n",x); ++x; printf("localstaticxis%donexitingb\n",x);}voidc(void){ printf("\nglobalxis%donenteringc\n",x); x*=10; printf("globalxis%donexitingc\n",x);}C程序设计基础教程第六章函数与宏定义**/49程序运行结果:后6次函数调用localxinais25afterenteringalocalxinais26beforeexitinga localstaticxis50onenteringblocalstaticxis51onexitingb globalxis1onenteringcglobalxis10onexitingc localxinais25afterenteringalocalxinais26beforeexitinga localstaticxis51onenteringblocalstaticxis52onexitingbglobalxis10onenteringcglobalxis100onexitingc最后一次输出:localxinmainis5C程序设计基础教程第六章函数与宏定义**/49二.变量的存储类型变量的存储类型:指的是变量的存储属性,它说明变量占用存储空间的区域。在内存中,供用户使用的存储区由程序区、静态存储区和动态存储区三部分组成。变量的存储类型有四种:auto型、register型、static型和extern型。auto型变量存储在内存的动态存储区。register型变量保存在寄存器中。static型变量和extern型变量存储在静态存储器。C程序设计基础教程第六章函数与宏定义**/49局部变量的存储类型缺省值为auto型。全局变量的存储类型缺省值为extern型。auto型变量和register型变量只用于定义局部变量。static型变量即可定义成局部变量,又可定义成全局变量。【例6-5】设计一个函数:longfac(intn),可用来计算1~5的阶乘。分析:可在函数中定义一个static型变量,用来保存上次的计算结果。C程序设计基础教程第六章函数与宏定义**/49/*exam6_5.c用static型变量保留上次阶乘的值*/#include<stdio.h>longfac(intn){ staticintf=1; f=f*n; returnf;}main(){ inti; for(i=1;i<=5;i++) printf("%d!=%ld\n",i,fac(i));}程序运行结果:1!=12!=23!=64!=245!=120局部变量f被定义成static型的,因此,它只在该函数第1次被调用的时候初始化其值为1,以后再调用该函数时,不再进行初始化,而是使用上一次调用的值。C程序设计基础教程第六章函数与宏定义**/49§6.3内部函数与外部函数一.内部函数若函数的存储类型为static型,则称其为内部函数或称静态函数,它表示在同一个程序中(由多个源文件组成),该函数只能在一个文件中存在,在其它文件中不可使用。如:staticintfun-name();内部函数只能被其所在的源文件调用。二.外部函数若函数的存储类型定义为extern型,则称其为外部函数,它表示该函数能被其它源文件调用。函数的缺省存储类型为extern型。注意:在需要用到外部函数的文件中,其函数声明必须用extern进行说明。C程序设计基础教程第六章函数与宏定义**/49例如:有两个源文件file1.c和file2.c如下所示:/*file1.c调用外部函数*/#include<stdio.h>intmod(inta,intb);externintadd(intm,intn);/*外部函数声明*/main(){intx,y,result;scanf(“%d%d”,&x,&y);result=add(x,y);/*调用外部函数*/if(result>0)result=result-mod(x,y);printf(“result=%d\n”,result);}C程序设计基础教程第六章函数与宏定义**/49intmod(inta,intb){return(a%d);}/*file2.c外部函数*/externintadd(intm,intn){return(m+n);}说明:1.在文件1(file1.c)中的函数声明:intmod(inta,intb);实际上相当于:externintmod(inta,intb);C程序设计基础教程第六章函数与宏定义**/492.在文件2(file2.c)中的函数定义:externintadd(intm,intn){return(m+n);}实际上相当于:intadd(intm,intn){return(m+n);}3.由多个源文件组成一个程序时,main()函数只能出现在一个源文件中。C程序设计基础教程第六章函数与宏定义**/494.多个源文件的连接方式有三种:①将各源文件分别编译成目标文件,得到多个目标文件(.obj后缀),然后用连接命令(tlink)把多个.obj文件连接起来,在Turboc上用如下命令:tlinkfile1.obj+file2.obj+…+filen.obj生成一个file1.exe的可执行文件。②建立项目文件(.prj后缀),具体操作可参阅各种C编译手册。③使用文件包含命令。C程序设计基础教程第六章函数与宏定义**/49§6.4递归函数设计和调用C语言中一个函数中的语句可以是对另一个函数的调用。函数嵌套调用图例:调用过程按图中箭头所示的方向和顺序进行,属于一种线性调用关系,每次调用后,最终返回到原调用点,继续执行以下语句。C程序设计基础教程第六章函数与宏定义**/49C语言中还允许在函数中调用自身,或函数之间相互调用,这种调用方式称之为递归。递归又分为直接递归调用和间接递归调用。直接递归调用;函数直接调用自身。间接递归调用:函数互相调用对方。直接递归:inttemp(intx){inty,z;……z=temp(y);……}C程序设计基础教程第六章函数与宏定义**/49间接递归:显然,递归有可能陷入无限递归状态,最终导致错误发生。因此,设计一个递归问题必须具备两个条件:1.后一部分与原始问题类似。2.后一问题是原始问题的简化。C程序设计基础教程第六章函数与宏定义**/49【例6-6】编程,从键盘输入一个正整数n,求n!。n!的数字表达式为:n!=定义一个求n!的函数:longfac(intn)longfac(intn){longresult;if(n==0||n==1)result=1;elseresult=n*fac(n-1);return(result);}C程序设计基础教程第六章函数与宏定义**/49完整程序如下:/*exam6_6.c用递归法求n!*/#include<stdio.h>longfac(intn){ longresult; if(n==0||n==1) result=1; else result=n*fac(n-1); returnresult;}main(){ intx; longf;C程序设计基础教程第六章函数与宏定义**/49 scanf("%d",&x); if(x<=0) printf("Yourinputiswrong!\n"); else { f=fac(x); printf("%d!=%ld\n",x,f); }}程序运行结果:66!=720C程序设计基础教程第六章函数与宏定义**/49【例6-7】求Fibonacci数列第i项的值。Fibonacci数列:0,1,1,2,3,5,8,13,21,…其数字表达式为:fibonacci(0)=0fibonacci(1)=1fibonacci(n)=fibonacci(n-1)+fibonacci(n-2)(n>1)设计一个函数:longfibonacci(intn)用于计算数列中第n项的值,C程序设计基础教程第六章函数与宏定义**/49程序如下所示:/*exam6_7.c求第n项Fibonacci数列的值*/#include<stdio.h>longfibonacci(intn);main(){ intx=0; longresult; do { result=fibonacci(x); printf("fibonacci(%d)=%ld\n",x,result); scanf("%d",&x); }while(x!=-1);}C程序设计基础教程第六章函数与宏定义**/49longfibonacci(intn){ if(n==0||n==1) returnn; else returnfibonacci(n-1)+fibonacci(n-2);}程序运行结果:fibonacci(0)=03fibonacci(3)=24fibonacci(4)=36C程序设计基础教程第六章函数与宏定义**/49以x=4为例,下图说明了fibonacci函数是怎样计算fibonacci(4)的。图中把fibonacci简写成f。C程序设计基础教程第六章函数与宏定义**/49§6.6综合范例【例6-12】在屏幕上画一个18×18大小的棋盘。程序如下:/*exam6_12.c在屏幕上画一个棋盘*/#include<stdio.h>#include<ctype.h>#include<conio.h>/*定义画棋盘所需的制表符*/#defineLU0xda/*左上角*/#defineRU0xbf/*右上角*/#defineLD0xc0/*左下角*/#defineRD0xd9/*右下角*/#defineL0xc3/*左边*/#defineR0xb4/*右边*/C程序设计基础教程第六章函数与宏定义**/49#defineU0xc2/*上边*/#defineD0xc1/*下边*/#defineCROSS0xc5/*十字叉*//*棋盘左上角坐标*/#defineMAP_X5#defineMAP_Y5voiddraw_cross(intx,inty);voiddraw_map();main(){textmode(C40);draw_map();}C程序设计基础教程第六章函数与宏定义**/49/*函数定义:*/voiddraw_map()/*画棋盘*/{ inti,j; for(i=0;i<19;i++) for(j=0;j<19;j++) draw_cross(i,j);}voiddraw_cross(intx,inty){gotoxy(x+MAP_X,y+MAP_Y); textcolor(GREEN); if(x==0&&y==0) { putch(LU);/*画左上角*/ return; }C程序设计基础教程第六章函数与宏定义**/49 if(x==0&&y==18) { putch(LD);/*画左下角*/ return; } if(x==18&&y==0) { putch(RU);/*画右上角*/ return; } if(x==18&&y==18) { putch(RD);/*画右下角*/ return; }C程序设计基础教程第六章函数与宏定义**/49 if(x==0) { putch(L);/*画左边*/ return; } if(x==18) { putch(R);/*画右边*/ return; } if(y==0) { putch(U);/*画上边*/ return; }C程序设计基础教程第六章函数与宏定义**/49 if(y==18) { putch(D);/*画下边*/ return; } putch(CROSS);/*画十字叉*/}程序中宏定义的制表符的值可从ASCⅡ码表中查得,如:0xbf为十六进制表示,它代表右上角制表符“┐”。该程序必须在纯DOS模式下运行,其运行结果是在屏幕上显示一个绿色的18×18大小的方格棋盘,如后图所示。C程序设计基础教程第六章函数与宏定义**/49该程序显示一个绿色的18×18大小的方格棋盘C程序设计基础教程第六章函数与宏定义**/49【例6-13】将一个字符串的字符反向输出到屏幕。采用递归函数调用方法,程序如下:/*exam6_13.c反向显示字符串*/#include<stdio.h>#include<string.h>voidbackwards(chars[],intindex);/*函数声明*/main(){ charstr[80];/*定义字符数组*/ intindex=0; strcpy(str,"Showthisstring.");/*字符串拷贝*/ backwards(str,index);/*函数调用*/}C程序设计基础教程第六章函数与宏定义**/49voidbackwards(chars[],intindex)/*函数定义*/{if(s[index]){ printf("%c",s[index]);/*输出字符*/ backwards(s,index+1);/*递归调用*/ printf("%c",s[index]);/*输出字符*/}}程序运行结果:Showthisstring..gnirtssihtwohSC程序设计基础教程第六章函数与宏定义**/49小结:介绍了函数的定义和传值调用函数的使用方法。注意:若用全局变量作为函数的参数,则在函数中可以使得该全局变量的值发生变化。对于递归函数的设计一定要有可使递归结束的条件,否则会使程序产生无限递归。使用预处理命令时,要注意以下几点:1.宏替换定义的末尾不能使用分号“;”。2.在有参数的宏定义中,参数加括号和不加括号有时会有区别。3.使用文件包含时,要避免出现变量和函数发生重定义的现象。4.要区分条件编译与条件语句的作用。
/
本文档为【C语言程序设计教程 教学课件 作者 李丽娟 第6章函数与宏定义】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索