c 语言 第六章函数与宏定义

上传人:痛*** 文档编号:244035526 上传时间:2024-10-02 格式:PPT 页数:49 大小:319KB
收藏 版权申诉 举报 下载
c 语言 第六章函数与宏定义_第1页
第1页 / 共49页
c 语言 第六章函数与宏定义_第2页
第2页 / 共49页
c 语言 第六章函数与宏定义_第3页
第3页 / 共49页
资源描述:

《c 语言 第六章函数与宏定义》由会员分享,可在线阅读,更多相关《c 语言 第六章函数与宏定义(49页珍藏版)》请在装配图网上搜索。

1、C,,程序设计基础教程,第六章,函数与宏定义,*,*,/49,第六章 函数与宏定义,,§,6.1 函数概念,,§,6.2 变量作用域和存储类型,,§,6.3 内部函数与外部函数,,§,6.4 递归函数设计和调用,,§,6.6 综合范例,,10/2/2024,1,,§,6.1 函数概念,,C,语言允许把问题设计成一个一个的模块,程序通过调用模块功能来解决问题。这些模块通常都是通过函数来实现的,又可称其为,函数模块,。,,C,语言中,函数可分为两类 :,一类是由系统定义的,标准函数,,又称为,库函数,,其函数声明一般是放在系统的,include,目录下以.,h,为后缀的

2、头文件中,如在程序中要用到某个库函数,必须在调用该函数之前用,#,include<,头文件名>,命令将库函数信息包含到本程序中。,另一类函数是,自定义函数,,两种形式:,第一种:,函数声明、函数调用、函数定义。,,第二种:,函数定义、函数调用。,10/2/2024,2,,§ 6.1.1 函数定义,,函数定义的一般形式可以有两种。,形式一:,[存储类型符] [返回值类型符] 函数名([形参说明表]),,{,,,函数语句体,,},形式二:,[存储类型符] [返回值类型型符] 函数名([形参表]),,,形参说明;,,{,,,函数语句体,,},10/2/2024,3,,说明:,,1.[,存储类型

3、符,]指的是函数的作用范围,它只有两种形式:,static,和,extern。,,static,说明函数只能作用于其所在的源文件,用,static,说明的函数又称为,内部函数,。,,extern,说明函数可被其它源文件中的函数调用,用,extern,说明的函数,又称为,外部函数,。,,缺省,情况为,extern。,2.[,返回值类型符,]指的是函数体语句执行完成后,,函数返回的值的类型,,如,int,, float, char,等等,若函数无返回值,则用,空类型,void,来定义函数的返回值。,,缺省,情况为,int,型。,10/2/2024,4,,3.,函数名,由任何合法的标识符构成。建议将

4、函数名的命名与函数内容有一定关系。,4.在第一种函数定义的形式中,[,形参说明表,]是一系列用逗号分开的每个形参变量说明。,,如:,int,x,,int,y,,int,z,,这表示形参变量有三个:,x, y, z。,它们的类型都是,int,型。,,在第二种函数定义的形式中,[,形参表],是一系列用逗号分开的形参变量。如:,x, y, z,5.,函数语句体,是放在一对花括号{ }中,由局部数据类型描述和功能实现两部分组成。,10/2/2024,5,,6.,函数返回语句,的形式有以下两种:,,①函数无返回值的情况:,return;,,②,函数有返回值的情况:,return(,表达式的值);,,在

5、第②种情况下要注意,“表达式的值”的类型必须与函数返回值的类型相一致。,例如:求两个任意整数的绝对值的和,用函数,abs_sum(),实现。,/*,直接调用库函数来计算,m,和,n,的绝对值 */,,int,abs_sum(,int,m,,int,n),,{,,return (abs(m)+abs(n));,,},,/*,函数,abs(),是在头文件,math.h,中声明的*/,10/2/2024,6,,函数定义如下:,,int,abs_sum(,int,m,,int,n),,{,,if (m<0),,m=-m;,,if(n<0),,n=-n;,,return(m+n);,,},§6.1.2

6、 函数声明和调用,,一.函数的声明,,函数声明的一般形式:,[存储类型符] [返回值类型符] 函数名([形参说明表]);,,如:,int,abs-sun(,int,m,,int,n);,10/2/2024,7,,二.函数调用,,函数调用是通过函数调用语句来实现的,分两种形式:,①无返回值的情况:,,函数名([实参表]);,,②有返回值的情况:,,变量名=函数名([实参表]);,,该变量名的类型必须与函数的返回值类型相同。,函数调用时都会去执行函数语句中的内容,函数执行完毕后,回到函数的调用处,继续执行下面的语句。,10/2/2024,8,,§6.1.3 函数的传值方式,,函数的传值方式,

7、:,,,采用实参表将每一个实参的值相应地传递给每一个形参变量,形参变量在接收到实参表传过来的值时,会在内存,临时开辟新的空间,,以保留形参变量的值,当函数执行完毕时,这些,临时开辟的内存空间会被释放,,并且形参的值在函数中不论是否发生变化,,都不会影响到实参变量的值的变化,,这就是函数的传值方式。,自定义函数在程序中的使用顺序有两种形式:,① 先进行函数声明,再进行函数调用,,函数定义放在函数调用之后。,函数声明在函数调用之前。,,②,函数定义放在函数调用之前。,10/2/2024,9,,【例6-1】 编程序,通过调用函数,abs-sum(),,求任意两个整数的绝对值的和。,/*,exam6_

8、1.c,调用函数求两整数绝对值的和*/,,#,include ,,int abs_sum(int m,int n);,,main(),,{ int x,y,z;,,scanf("%d%d",,,z=abs_sum(x,y);,,printf("sum is %d",z);,,},,int abs_sum(int m,int n),,{ if(m<0),,m=-m;,,if(n<0),,n=-n;,,return m+n;,,},程序运行结果:,,7 12,,,sum is 19,10/2/2024,10,,用传值方式调用函数时,实参也可以是函数调用语句,,【例6-2】求任意三个数的绝对值的

9、和。,/*,exam6_2.c,调用函数求三个整数绝对值的和*/,,#,include ,,int abs_sum(int m,int n);,,main(),,{ int x,y,z,sum;,,scanf("%d%d%d",,,sum=abs_sum(,abs_sum(x,y),,z);,,printf("sum is %d",sum);,,},,int abs_sum(int m,int n),,{ if(m<0),,m=-m;,,if(n<0),,n=-n;,,return m+n;,,},程序运行结果:,,7 12 5,,,sum is 24,10/2/2024,11,,注意:

10、,对于有返回值的函数,调用时若没有把它赋给某个变量,仍然是可以的,只是函数的返回值有可能会被丢失。,【例6-3】 求任意两数的乘积。,自定义一个函数,mul,(),,用于求两数的乘积,程序:,,/*,exam6_3.c,求两个数的乘积*/,,#,include ,,float mul(float a,float b);,,main(),,{ float x,y,z;,,scanf("%f %f",,,z=mul(x,y);,/* ① */,,x=x+10;,,y=y-10;,,mul(x,y); /*,② */,10/2/2024,12,,,x=x*2;,,y=y*2;,,p

11、rintf("z=%f,mul(%f,%f)=%f\n",z,x,y,mul(x,y)); /*,③,* /,,},,float mul(float a,float b),,{ return a*b;,,},程序运行结果:,,5 6,,,z=30.000000,mul(30.000000,-8.000000)=-240.000000,10/2/2024,13,,程序说明,:,注释①处调用函数后的返回值赋给变量,z。,注释②处调用函数后的返回值没有赋给任何变量,函数的返回值被丢失。,注释③处调用函数后的返回值成为了,printf,(),函数的参数。,10/2/202

12、4,14,,§,6.2 变量作用域和存储类型,,一.变量的作用域,变量的作用域:指的是,变量的有效范围,,针对变量不同的作用域,可把变量分为局部变量和全局变量。,局部变量,:在函数内部或某个控制块的内部定义的变量为局部变量,局部变量的有效范围只限于,本函数内部,,退出函数,该变量自动失效。,全局变量,:在函数外面定义的变量称为全局变量,全局变量的作用域是从该变量定义的位置开始,直到源文件结束。在,同一文件,中的所有函数都可以引用全局变量。,,10/2/2024,15,,局部变量和全局变量的,作用域,如图所示:,10/2/2024,16,,【例6-4】 变量作用域应用举例,阅读下面的程序,注

13、意区分局部变量和全局变量的作用域。,/*,exam6_4.c,变量作用域举例*/,,#,include ,,void a( void );,,void b( void );,,void c( void );,,int x = 1;,,main(),,{,,int x = 5;,,printf("local x in outer scope of main is %d\n", x );,10/2/2024,17,,{,,,int x = 7;,,printf( "local x in inner scope of main is %d\n", x );,,},,printf( "local x

14、in outer scope of main is %d\n", x );,,a();,,b();,,c();,,a();,,b();,,c();,前三次,输出,结果:,,local x in outer scope of main is 5,,local x in inner scope of main is 7,,local x in outer scope of main is 5,10/2/2024,18,,,printf( "local x in main is %d\n", x );,,getchar();,,return 0;,,},,void a( void ),,{,,int

15、 x = 25;,,printf( "\nlocal x in a is %d after entering a\n", x );,,++x;,,printf( "local x in a is %d before exiting a\n", x );,,},10/2/2024,19,,void b( void ),,{,,static int x = 50;,,printf( "\nlocal static x is %d on entering b\n", x );,,++x;,,printf( "local static x is %d on exiting b\n", x );,,},

16、,void c( void ),,{,,printf( "\nglobal x is %d on entering c\n", x );,,x *= 10;,,printf( "global x is %d on exiting c\n", x );,,},10/2/2024,20,,程序运行结果:,,后6次,函数调用,local x in a is 25 after entering a,,local x in a is 26 before exiting a,,local static x is 50 on entering b,,local static x is 51 on exiti

17、ng b,,global x is 1 on entering c,,global x is 10 on exiting c,,local x in a is 25 after entering a,,local x in a is 26 before exiting a,,local static x is 51 on entering b,,local static x is 52 on exiting b,,global x is 10 on entering c,,global x is 100 on exiting c,最后一次输出:,,local x in main is 5,10

18、/2/2024,21,,二.变量的存储类型,变量的存储类型:指的是变量的,存储属性,,它说明,变量占用存储空间的区域。,在内存中,供用户使用的存储区由,程序区,、,静态存储区,和,动态存储区,三部分组成。,变量的存储类型有四种:,auto,型、,register,型、,static,型和,extern,型。,auto,型,变量存储在内存的,动态存储区,。,,register,型变量保存在,寄存器,中。,,static,型变量和,extern,型变量,存储在,静态存储器,。,10/2/2024,22,,局部变量,的存储类型缺省值为,auto,型 。,,全局变量,的存储类型缺省值为,extern,

19、型 。,auto,型变量和,register,型变量只用于定义局部变量。,,static,型变量即可定义成局部变量,又可定义成全局变量。,【例6-5】 设计一个函数:,long,fac,(,int,n),,可用来计算1~5的阶乘。,分析:可在函数中定义一个,static,型变量,用来保存上次的计算结果。,10/2/2024,23,,/*,exam6_5.c,用,static,型变量保留上次阶乘的值*/,,#,include ,,long fac(int n),,{,,static int f=1;,,f=f*n;,,return f;,,},,main(),,{ int i;,,for(i=

20、1;i<=5;i++),,printf("%d!=%ld\n",i,fac(i));,,},程序运行结果:,,1!=1 2!=2 3!=6 4!=24 5!=120,局部变量,f,被定义成,static,型的,因此,它只在该函数第1次被调用的时候初始化其值为1,以后再调用该函数时,不再进行初始化,而是使用上一次调用的值。,,10/2/2024,24,,§,6.3 内部函数与外部函数,,一.内部函数,若函数的存储类型为,static,型,则称其为,内部函数,或称,静态函数,,它表示在同一个程序中(由多个源文件组成),该函数只能在一个文件中存在,在其它文件中不可使用。,如:,stati

21、c,int,fun-name();,,内部函数只能被其所在的源文件调用。,二.外部函数,若函数的存储类型定义为,extern,型,则称其为,外部函数,,它表示该函数能被其它源文件调用。函数的缺省存储类型为,extern,型。,注意:,在需要用到外部函数的文件中,其函数声明必须用,extern,进行说明。,10/2/2024,25,,例如:有两个源文件,file1.c,和,file2.c,如下所示:,/*,file1.c,调用外部函数*/,,#,include <,stdio,.h>,,int,mod(,int,a,,int,b);,,extern,int,add (,int,m,,int,n)

22、; /*,外部函数声明*/,,main(),,{,,,int,x, y, result;,,,scanf,(“%d%d”, ,,result=add(x,y); /*,调用外部函数*/,,,if (result >0),,result=result-mod(x,y);,,,printf,(“result=%d\n”, result);,,},10/2/2024,26,,int,mod(,int,a,,int,b),,{,,return(a%d);,,},,/* file2.c,外部函数*/,,extern,int,add(,int,m,,int,n),,{,,return(m+n);,,},说

23、明:,1.在文件1(,file1.c),中的函数声明:,,,int,mod(,int,a,,int,b);,,实际上相当于:,extern,int,mod(,int,a,,int,b);,10/2/2024,27,,2.在文件2(,file2.c),中的函数定义:,,,extern,int,add(,int,m,,int,n),,{,,return(m+n);,,},,实际上相当于:,int,add(,int,m,,int,n),,{,,return(m+n);,,},3.由多个源文件组成一个程序时,,main(),函数只能出现在一个源文件中。,10/2/2024,28,,4.多个源文件的连接

24、方式有三种:,①,将各源文件分别编译成目标文件,得到多个目标文件(.,obj,后缀),然后用连接命令(,tlink,),把多个.,obj,文件连接起来,在,Turbo c,上用如下命令:,,,tlink,file1.,obj,+file2.,obj,+…+,filen,.,obj,,生成一个,file1.exe,的可执行文件。,②建立项目文件(.,prj,后缀),具体操作可参阅各种,C,编译手册。,③使用文件包含命令。,10/2/2024,29,,§,6.4 递归函数设计和调用,,C,语言中一个函数中的语句可以是对另一个函数的调用。,函数嵌套调用,图例:,调用过程按图中箭头所示的方向和顺序

25、进行,属于一种,线性调用关系,,每次调用后,最终返回到原调用点,继续执行以下语句。,10/2/2024,30,,C,语言中还允许在函数中,调用自身,,或函数之间相互调用,这种调用方式称之为,递归,。递归又分为,直接递归调用,和,间接递归调用,。,直接递归调用;函数直接调用自身。,间接递归调用:函数互相调用对方。,直接递归:,int,temp (,int,x),,{,,,int,y, z;,,……,,z=temp(y);,,……,,},10/2/2024,31,,间接递归:,显然,递归有可能陷入无限递归状态,最终导致错误发生。因此,,设计一个递归问题必须具备两个条件,:,1.后一部分与原始问题类

26、似。,,2.后一问题是原始问题的简化。,10/2/2024,32,,【例6-6】 编程,从键盘输入一个正整数,n,,求,n!。,n!,的数字表达式为:,,n!=,定义一个求,n!,的函数:,long,fac,(,int,n),,long,fac,(,int,n),,{ long result;,,if (n= = 0 || n= =1),,result =1;,,else,,result=n*,fac,(n-1);,,return(result);,,},10/2/2024,33,,完整程序如下:,/*,exam6_6.c,用递归法求,n!*/,,#include ,,long fac(i

27、nt n),,{,,long result;,,if(n==0||n==1),,result=1;,,else,,result=n*fac(n-1);,,return result;,,},,main(),,{ int x;,,long f;,10/2/2024,34,,,scanf("%d",,,if(x<=0),,printf("Your input is wrong!\n");,,else,,{,,f=fac(x);,,printf("%d!=%ld\n",x,f);,,},,},程序运行结果:,,6,,,6!=720,10/2/2024,35,,【例,6-7,】,,求,Fibonac

28、ci,数列第,i,项的值。,,Fibonacci,数列,:0, 1, 1, 2, 3, 5, 8, 13, 21,…,其数字表达式为,:,,,fibonacci,(0)=0,,,fibonacci,(1)=1,,,fibonacci,(n)=,fibonacci,(n-1)+,fibonacci,(n-2) (n>1),设计一个函数:,long,fibonacci,(,int,n),用于计算数列中第,n,项的值,,10/2/2024,36,,程序如下所示:,/*,exam6_7.c,求第,n,项,Fibonacci,数列的值*/,,#,include ,,long fibonacci(int

29、 n);,,main(),,{ int x=0;,,long result;,,do,,{ result=fibonacci(x);,,printf("fibonacci(%d)=%ld\n",x,result);,,scanf("%d",,,}while(x!=-1);,,},10/2/2024,37,,long fibonacci(int n),,{,,if(n==0||n==1),,return n;,,else,,return fibonacci(n-1)+fibonacci(n-2);,,},程序运行结果:,,fibonacci(0)=0,,3,,,fibonacci(3)=2,,

30、4,,,fibonacci(4)=3,,6,,10/2/2024,38,,以,x=4,为例,下图说明了,fibonacci,函数是怎样计算,fibonacci,(4),的。图中把,fibonacci,简写成,f。,10/2/2024,39,,§,6.6 综合范例,【例6-12】 在屏幕上画一个18×18大小的棋盘。,程序如下:,/*,exam6_12.c,在屏幕上画一个棋盘*/,,#,include ,,#include ,,#include ,,/*,定义画棋盘所需的制表符*/,,#,define LU 0xda /*,左上角*/,,#,define RU 0xbf /*,右上角

31、*/,,#,define LD 0xc0 /*,左下角*/,,#,define RD 0xd9 /*,右下角*/,,#,define L 0xc3 /*,左边*/,,#,define R 0xb4 /*,右边*/,10/2/2024,40,,#,define U 0xc2 /*,上边*/,,#,define D 0xc1 /*,下边*/,,#,define CROSS 0xc5 /*,十字叉*/,,/*棋盘左上角坐标*/,,#,define MAP_X 5,,#define MAP_Y 5,,void draw_cross(int x,int y);,,void draw

32、_map();,,main(),,{,,textmode(C40);,,draw_map();,,},10/2/2024,41,,/*函数定义:*/,,void draw_map() /*,画棋盘*/,,{,,,int i,j;,,for(i=0;i<19;i++),,for(j=0;j<19;j++),,,draw_cross(i,j);,,},,void draw_cross(int x,int y),,{ gotoxy(x+MAP_X,y+MAP_Y);,,textcolor(GREEN);,,if(x==0 && y==0),,{,,putch(LU); /*,画左上角*/,,,re

33、turn;,,},10/2/2024,42,,,if(x==0 && y==18),,{,,putch(LD); /*,画左下角*/,,,return;,,},,if(x==18 && y==0),,{,,putch(RU); /*,画右上角*/,,,return;,,},,if(x==18 && y==18),,{,,putch(RD); /*,画右下角*/,,,return;,,},10/2/2024,43,,,if(x==0),,{,,putch(L); /*,画左边*/,,,return;,,},,if(x==18),,{,,putch(R); /*,画右边*/,,,return;,,

34、},,if(y==0),,{,,putch(U); /*,画上边*/,,,return;,,},10/2/2024,44,,,if(y==18),,{,,putch(D); /*,画下边*/,,,return;,,},,putch(CROSS); /*,画十字叉*/,,},程序中,宏定义的制表符的值,可从,ASCⅡ,码表中查得,如:0,xbf,为十六进制表示,它代表右上角制表符“┐”。,该程序必须在纯,DOS,模式下运行,其运行结果是在屏幕上显示一个绿色的18×18大小的方格棋盘,,,如后图所示。,10/2/2024,45,,该程序显示一个绿色的18×18大小的方格棋盘,10/2/2024,

35、46,,【例6-13】 将一个字符串的字符反向输出到屏幕。,采用递归函数调用方法,程序如下:,/*,exam6_13.c,反向显示字符串*/,,#,include ,,#include ,,void backwards(char s[],int index); /*,函数声明*/,,main(),,{,,char str[80];/*,定义字符数组*/,,,int index = 0;,,strcpy(str,"Show this string."); /*,字符串拷贝*/,,,backwards(str,index); /*,函数调用*/,,},10/2/2024,47,,void bac

36、kwards(char s[],int index) /*,函数定义*/,,{,,,if (s[index]),,{,,printf("%c",s[index]); /*,输出字符*/,,,backwards(s,index+1); /*,递归调用*/,,,printf("%c",s[index]); /*,输出字符*/,,},,},程序运行结果:,,Show this string..gnirts siht wohS,10/2/2024,48,,小结,:,介绍了函数的定义和传值调用函数的使用方法 。,注意:若用全局变量作为函数的参数,则在函数中可以使得该全局变量的值发生变化。,对于递归函数的设计一定要有可使递归结束的条件,否则会使程序产生无限递归。,使用预处理命令时,要注意以下几点:,,1.宏替换定义的末尾不能使用分号“;”。,,2.在有参数的宏定义中,参数加括号和不加括号有时会有区别。,,3.使用文件包含时,要避免出现变量和函数发生重定义的现象。,,4.要区分条件编译与条件语句的作用。,10/2/2024,49,,

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

相关资源

更多
正为您匹配相似的精品文档
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

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

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


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