第三版C语言PPT课件讲解第08章+函数

上传人:鲁** 文档编号:569847480 上传时间:2024-07-31 格式:PPT 页数:61 大小:1.16MB
返回 下载 相关 举报
第三版C语言PPT课件讲解第08章+函数_第1页
第1页 / 共61页
第三版C语言PPT课件讲解第08章+函数_第2页
第2页 / 共61页
第三版C语言PPT课件讲解第08章+函数_第3页
第3页 / 共61页
第三版C语言PPT课件讲解第08章+函数_第4页
第4页 / 共61页
第三版C语言PPT课件讲解第08章+函数_第5页
第5页 / 共61页
点击查看更多>>
资源描述

《第三版C语言PPT课件讲解第08章+函数》由会员分享,可在线阅读,更多相关《第三版C语言PPT课件讲解第08章+函数(61页珍藏版)》请在金锄头文库上搜索。

1、第三版第三版C语言语言PPT课件课件讲解第讲解第08章章+函数函数8.1概述概述函数函数:英文名为英文名为Function,直译为直译为“功能功能”,“函数函数”的意思的意思.在在C语语言里言里,函数指的是函数指的是实现一个特定功能的程序模块实现一个特定功能的程序模块.它相当于其他语它相当于其他语言中的子程序言中的子程序.一个一个C语言程序可由一个语言程序可由一个主函数主函数和若干个函数构成和若干个函数构成,其中主函其中主函数是不可缺省的数是不可缺省的.每个每个C程序由主函数调用其他函数程序由主函数调用其他函数,其他函数也可其他函数也可以相互调用以相互调用.在程序设计中在程序设计中,常将一些常

2、用的功能模块编写成函数常将一些常用的功能模块编写成函数,放在函放在函数库中供公共选用数库中供公共选用.main函数函数a函数函数e函数函数f函数函数g.函数函数b函数函数h函数函数I函数函数J.函数函数c函数函数K 函数函数L 函数函数M.main()voidprintstar();voidprint_message();printstar();print_message();printstar();voidprintstar()printf(“*n”);voidprint_message()printf(“Howdoyoudo!n”);说明说明:1)源程序文件可由一个或多个函数组成源程序文件

3、可由一个或多个函数组成,其中其中主函数是不可缺省主函数是不可缺省的的.源程序文件是编译单位源程序文件是编译单位,函数函数不是编译单位不是编译单位;2)一个一个C程序由一个或多个源程序文件组成程序由一个或多个源程序文件组成.较较大的大的C程序程序,常将一些函数和其他内容分别放在若干常将一些函数和其他内容分别放在若干源文件中源文件中,再由若干源文件组成一个再由若干源文件组成一个C程序程序.最简单的情况最简单的情况,一个一个C程序由一个源程序组成程序由一个源程序组成,这个源程序中只包含了一个函数这个源程序中只包含了一个函数-主函数主函数;3)C程序的执行程序的执行从从main函数开始函数开始,在在m

4、ain函数函数中结束中结束.4)所有函数在定义时是所有函数在定义时是相互独立相互独立的的,函数之间函数之间可以相互引用但不能可以相互引用但不能嵌套定义嵌套定义;函数的分类函数的分类:1)从从用户使用的角度用户使用的角度函数可分为函数可分为:标准函数标准函数:即即库函数库函数.由系统提供由系统提供,用户不必定义用户不必定义,直接使用直接使用;用户自定义函数用户自定义函数:由用户根据需要由用户根据需要,自行编写自行编写,以解决专门需要以解决专门需要;2)从从函数的形式函数的形式分分,函数可分为函数可分为:无参数函数无参数函数:在调用无参函数时在调用无参函数时,主函数并不将数据传送给被调用主函数并不

5、将数据传送给被调用函数函数,一般用来执行指定的一组操作一般用来执行指定的一组操作.无参函数可以带回也可以无参函数可以带回也可以不带回函数值不带回函数值,一般以后者居多一般以后者居多;有参函数有参函数:在调用函数时在调用函数时,在主函数和被调用函数之间有数据传递在主函数和被调用函数之间有数据传递;8.2函数定义的一般形式函数定义的一般形式1.无参函数的定义形式无参函数的定义形式类型标识符类型标识符函数名函数名()声明部分声明部分语句语句其中,用其中,用“类型标识符类型标识符”指定函数值的类型指定函数值的类型,即函数带回来的类,即函数带回来的类型型.无参函数一般不需要带回函数值无参函数一般不需要带

6、回函数值,因此可以不写类型标识符因此可以不写类型标识符;2.有参函数定义的一般形式有参函数定义的一般形式类型标识符类型标识符函数名函数名(形式参数表列形式参数表列)声明部分声明部分语句语句例如例如:intmax(intx,inty)intz;z=xy?x:y;return(z);3.可以有可以有“空函数空函数”形式为形式为:类型说明符类型说明符函数名函数名()例如例如:dummy() ;调用此函数时调用此函数时,什么工作也不做什么工作也不做,没有任何实际作用没有任何实际作用.此中空函数的使用一般用于程序设计的模块设计阶段此中空函数的使用一般用于程序设计的模块设计阶段;8.3函数参数和函数的值函

7、数参数和函数的值8.3.1形式参数和实际参数形式参数和实际参数1、形式参数(形参):、形式参数(形参):函数定义时函数定义时设定的参数。设定的参数。下下例例中中,函函数数头头intmax(intx,inty)中中x,y就就是是形形参参,它们的类型都是整型。它们的类型都是整型。2、实际参数(实参):、实际参数(实参):调用函数时调用函数时所使用的实际的参数。所使用的实际的参数。下下 例例 中中 , 主主 函函 数数 中中 调调 用用 max函函 数数 的的 语语 句句 是是 :nmax=max(a,b);其中其中a,b就是实参,它们的类型都是整型。就是实参,它们的类型都是整型。例例8.2调用函数

8、时的数据传递调用函数时的数据传递main()inta,b,c;scanf(“%d,%d”,&a,&b);c=max(a,b);printf(“Maxis%d”,c)intmax(intx,inty)intz;z=xy?x:y;return(z);运行情况如下运行情况如下:7,8Maxis8实参a,b形参x,yc=max(a,b);-实参实参:在运行时 把函数的max(intx,inty)把值传给函数. 结果赋给 函数名returu(z);形参形参:通知系统 要预留内存位置. 关于形参和实参的说明关于形参和实参的说明(1)只用在只用在发生函数调用时发生函数调用时,形参才被分配内存单元形参才被分配

9、内存单元.在调用结束后在调用结束后,形参所占的内存单元也被释放形参所占的内存单元也被释放;(2)实参可以是常量实参可以是常量,变量或表达式变量或表达式,如如:max(3,a+b)但要求它们有但要求它们有确定的值确定的值.在调用时将实参的值赋在调用时将实参的值赋给形参给形参.(3)在被定义的函数中在被定义的函数中,必须指定形参的类型必须指定形参的类型.(4)实参和形参的实参和形参的类型应相同或赋值兼容类型应相同或赋值兼容,否则会出错否则会出错;(5)C语言规定语言规定,实参对形参变量的数据传递是实参对形参变量的数据传递是“值传递值传递”,即即单向传递单向传递,只能由实参传给形参只能由实参传给形参

10、,而不能由形参传而不能由形参传回来回来.8.3.2函数的返回值函数的返回值通常通常,希望通过函数调用使主调函数得到一个确定的值希望通过函数调用使主调函数得到一个确定的值,这这就是函数的返回值就是函数的返回值.例如例例如例8.2.说明说明:(1)函数的返回值是通过函数中的函数的返回值是通过函数中的return语句语句获得的获得的.(2)一个函数中可以有一个函数中可以有一个以上一个以上的的return语句语句;执行到那一句,执行到那一句,那一句起作用。那一句起作用。(3)return语句后的括号可以不要语句后的括号可以不要;例如例如:returnz;和和return(z);是等效的是等效的.(4)

11、函数返回值的类型应当在函数返回值的类型应当在定义函数值时指定定义函数值时指定;在定义函数时在定义函数时对函数值说明的类型一般应该和对函数值说明的类型一般应该和return语句中的表达式类型一语句中的表达式类型一致致,如果不一致如果不一致,则则以函数类型为准以函数类型为准.(5)如果被调用函数中没有如果被调用函数中没有return语句语句,并不带回一个确定的、并不带回一个确定的、用户所希望的值;带回的是一个不确定的值。用户所希望的值;带回的是一个不确定的值。C语言允许用户语言允许用户把该值赋给变量把该值赋给变量.(6)为了明确表示为了明确表示“不带回值不带回值”,可以用可以用“void”定义无类

12、型定义无类型.例例如如:例例8.1中的定义可以改为中的定义可以改为:voidprintstar()voidprint_message()这样这样,系统就保证不使函数带回任何值系统就保证不使函数带回任何值,即禁止在主调函即禁止在主调函数中使用被调用函数的返回值数中使用被调用函数的返回值.例如例如:a=printstar();b=print_message();是不合法的是不合法的.8.4函数的调用函数的调用8.4.1函数调用的一般形式函数调用的一般形式函数调用的一般形式为函数调用的一般形式为:函数名函数名(实参表列实参表列)说明说明:(1)如果是调用无参函数如果是调用无参函数,则则“实参表列实参

13、表列”可以没有可以没有,但但括号不括号不能省略能省略;(2)如果实参表列多个实参如果实参表列多个实参,则各参数间用则各参数间用逗号隔开逗号隔开,实参与实参与形参的形参的个数应相等个数应相等,类型应一致类型应一致;在在TurboC中中,对实参求值的顺序对实参求值的顺序是按是按自右至左自右至左顺序求值的顺序求值的。见例。见例8.4。8.4.2函数调用的方式函数调用的方式按函数在程序中出现的位置来分按函数在程序中出现的位置来分,可以有以下三种函数调用可以有以下三种函数调用方式方式:1.函数语句函数语句把函数调用作为一个语句把函数调用作为一个语句.如例如例8.1中的中的printstar();这种不要

14、求函数带回值这种不要求函数带回值,只要求函数只要求函数完成一定的操作完成一定的操作;2.函数表达式函数表达式函数出现在一个表达式中函数出现在一个表达式中,这种表达式称为这种表达式称为函数表达式函数表达式,这是要这是要求函数求函数带回一个确定的值带回一个确定的值参加表达式的运算参加表达式的运算.例如例如:c=2*max(a,b);3.函数参数函数参数函数调用函数调用作为一个函数的实参作为一个函数的实参.这种调用的实质也是函数表达这种调用的实质也是函数表达式调用的一种式调用的一种.例如例如:m=max(a,max(b,c);其中其中max(b,c)是一次函数调用,它的值作为是一次函数调用,它的值作

15、为max另一次调用的另一次调用的实参。实参。8.4.3对被调用函数的声明和函数原型对被调用函数的声明和函数原型在一个函数中调用另一个函数需要具备的条件:在一个函数中调用另一个函数需要具备的条件:(1)首先被调用的函数必须是已经存在的函数首先被调用的函数必须是已经存在的函数(库函数库函数或或用用户自己定义的函数户自己定义的函数););(2)如果使用库函数,一般还应该在本文件开头用如果使用库函数,一般还应该在本文件开头用#include命令将调用有关库函数时所用到的信息命令将调用有关库函数时所用到的信息“包含包含”到本文件中来。到本文件中来。例如:例如:#include其中其中“stdio.h”是

16、一个是一个“头文件头文件”,在,在stdio.h文件中放了文件中放了输入输入输出库函数输出库函数所用到的一些宏定义。如果不包含所用到的一些宏定义。如果不包含“stdio.h”文件文件中的信息,就无法使用输入输出库中的函数。同样,使用数中的信息,就无法使用输入输出库中的函数。同样,使用数学库中的函数,应该用:学库中的函数,应该用:#include(3)如果使用用户自己定义的函数,如果使用用户自己定义的函数,函数调用与函数定义函数调用与函数定义前前,一般还应该在主调函数中对被调用函数作,一般还应该在主调函数中对被调用函数作声明声明。例例8.5main()floatadd(floatx,floaty

17、);floata,b,c;scanf(“%f,%f”,&a,&b);c=add(a,b);printf(“sumis%f”,c);floatadd(floatx,floaty)floatz;z=x+y;return(z);对被调用函数的声明。从此行开始为对被调用函数的定义。包括函数首部、函数体等。函数声明也称为函数声明也称为函数原型,函数原型,其作用主要是在程序的其作用主要是在程序的编译阶段对调用函数的合法性进行全面检查。编译阶段对调用函数的合法性进行全面检查。在函数声明中也可以不写形参名,而只写形参的类型。在函数声明中也可以不写形参名,而只写形参的类型。如上例中可以这样进行函数声明:如上例中

18、可以这样进行函数声明:floatadd(float,float);函数原型的一般形式为:函数原型的一般形式为:(1)函数类型函数类型函数名(参数类型函数名(参数类型1,参数类型参数类型2)(2)函数类型函数类型函数名(参数类型函数名(参数类型1参数名参数名1,参数类型参数类型2参数名参数名2)编译系统不检查参数名编译系统不检查参数名。因此上例程序中函数声明。因此上例程序中函数声明可以写成:可以写成:floatadd(floata,floatb);应当保证应当保证函数原型与函数首部写法上的一致函数原型与函数首部写法上的一致,即函,即函数类型、函数名,参数个数,参数类型和参数顺序必须数类型、函数名

19、,参数个数,参数类型和参数顺序必须相同。函数调用时函数名、实参个数应与函数原型一致。相同。函数调用时函数名、实参个数应与函数原型一致。实参类型必须与函数原型中的参数类型赋值兼容。实参类型必须与函数原型中的参数类型赋值兼容。如果如果被调用函数的定义出现在主调函数之前被调用函数的定义出现在主调函数之前,可以不必加以声明可以不必加以声明。8.5函数的嵌套调用函数的嵌套调用C语言的函数定义都是互相平行、独立的。语言的函数定义都是互相平行、独立的。C语句不语句不能嵌套定义函数,但能嵌套定义函数,但可以嵌套调用函数可以嵌套调用函数,也就是说,在,也就是说,在调用一个函数的过程中,又调用另一个函数。调用一个

20、函数的过程中,又调用另一个函数。下图表示的是两层嵌套(连下图表示的是两层嵌套(连main函数共函数共3层函数),层函数),其执行过程见图。其执行过程见图。开始开始调用调用a函数函数结束结束开始开始调用调用b函数函数结束结束开始开始结束结束main函数a函数b函数具体的例子请参考具体的例子请参考P168例例8.68.6函数的递归调用函数的递归调用在调用一个函数的过程中又出现直接或间接地调用该在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的函数本身,称为函数的递归调用递归调用。C语言的特点之一就在语言的特点之一就在于允许函数的递归调用。例如:于允许函数的递归调用。例如:intf(

21、intx)inty,z;z=f(y);return(2*z);在调用函数在调用函数f的过程中,又要调用的过程中,又要调用f函数,这是直接调函数,这是直接调用本函数用本函数.见图。见图。开始开始调用调用f函数函数f 函数在调用在调用f1函数过程中要调用函数过程中要调用f2函数,而在调用函数,而在调用f2函数过程中又要调用函数过程中又要调用f1函数。函数。从图上可以看到,这两种递归调用都是从图上可以看到,这两种递归调用都是无终止无终止的自的自身调用。可以身调用。可以用用if语句来控语句来控制制,只有在某一条件成立,只有在某一条件成立时才继续执行递归调用,否则就不再继续。时才继续执行递归调用,否则就

22、不再继续。开始开始调用调用f2函数函数开始开始调用调用f1函数函数f1 函数f2 函数例例8.7有有5个人坐在一起,问第个人坐在一起,问第5个人多少岁?他说比第个人多少岁?他说比第4个人大个人大2岁。问第岁。问第4个人岁数,他说比第个人岁数,他说比第3个人大个人大2岁。问岁。问第第3个人,又说比第个人,又说比第2个人大个人大2岁。问第岁。问第2个人,说比个人,说比第第1个个人大人大2岁。最后问第岁。最后问第1个人,他说是个人,他说是10岁。请问第岁。请问第5个人多个人多大。大。显然,这是一个递归问题。每一个年龄都比其前显然,这是一个递归问题。每一个年龄都比其前1个人的个人的年龄大年龄大2岁即岁

23、即age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10因此,除了第一个人,其余的人的年龄都需用递归法求因此,除了第一个人,其余的人的年龄都需用递归法求出。出。执行过程如下:执行过程如下:age函数函数n=5mainage(5)输出输出age(5)c=age(4)+2age函数函数n=4c=age(3)+2age函数函数n=3c=age(2)+2age函数函数n=2c=age(1)+2age函数函数n=1c=10age(2)=12age(3)=14age(4)=16age(5)=18intage(intn)/*

24、递归函数递归函数*/intc;if(n=1)c=10;elsec=age(n-1)+2;return(c);main()/*主函数主函数*/printf(“%d”,age(5)递归结束条件递归结束条件递归公式递归公式递归函数编写总结:递归函数编写总结:1)采用采用if语句格式;语句格式;2)两要素:两要素:递归结束条件递归结束条件递归公式递归公式3)一般形式一般形式if(递归结束条件递归结束条件)else递归公式递归公式4)递归公式中包含递归函数递归公式中包含递归函数名,但参数不同名,但参数不同5)if语句前的语句在递归进语句前的语句在递归进入时执行,入时执行,if语句后的语句语句后的语句在递

25、归返回时执行在递归返回时执行例例8.8用递归的方法求用递归的方法求n!递推法:递推法:从从1开始,乘开始,乘2,乘,乘3,一直乘到一直乘到n。其基本。其基本原理是从一个已知事实推出下一个事实。原理是从一个已知事实推出下一个事实。递归法:递归法:当当n=1或或0时,时,n!=1;当;当n1时,时,n!=n*(n-1)!。floatfac(intn)floatf;if(n0)printf(“n0,dataerror!”);elseif(n=0|n=1)f=1;else f=fac(n-1)*n;return(f);main()intn;floaty;printf(“inputaintegernum

26、ber:”;scanf(“%d”,&n);y=fac(n);printf(“%d!=%15.0f”,n,y);例例8.9汉诺塔问题汉诺塔问题8.7数组作为函数参数数组作为函数参数1.数组元素作为函数实参数组元素作为函数实参数组元素数组元素作函数实参:作函数实参:“值传递值传递”方式,即单向传递方式,即单向传递。用法与变量相同。用法与变量相同。例例8.10有两个数组有两个数组a,b,各有,各有10个元素,将它们对应地个元素,将它们对应地逐个相比。如果逐个相比。如果a数组中的元素大于数组中的元素大于b数组中的相应元素数组中的相应元素的数目多于的数目多于b数组中元素中大于数组中元素中大于a数组中相应

27、元素的数目,数组中相应元素的数目,则认为则认为a数组大于数组大于b数组,并分别统计出两个数组相应元数组,并分别统计出两个数组相应元素大于、等于、小于的次数。素大于、等于、小于的次数。分析分析:1)对于两个数组中的元素比较结果,我们可以用对于两个数组中的元素比较结果,我们可以用3个变量来记录;个变量来记录;2)为了保持程序的简洁,用一个函数来进行数组为了保持程序的简洁,用一个函数来进行数组元素的比较,比较结果用该函数的返回值表示。元素的比较,比较结果用该函数的返回值表示。main ( )int large(int x,int y);int a10,b10,i,n=0,m=0,k=0;printf

28、(“enter array a:n”); for(i=0;i10;i+)scanf(“%d”,&ai);printf(“n”);printf(“enter array b:n”); for(i=0;i10;i+)scanf(“%d”,&bi);printf(“n”);for(i=0;ibi%d timesn ai=bi%d timesn aik)printf(“array a is larger than array bn”);if(ny) flag=1;else if (xy) flag= -1;else flag=0;return(flag);输入数组输入数组a和数组和数组b的数据的数据调

29、用调用large函数进行函数进行数组元素比较数组元素比较large函数,返回比较结果函数,返回比较结果2.数组名可作函数参数数组名可作函数参数数组名可作函数参数,此时数组名可作函数参数,此时实参与形参应用数组名或实参与形参应用数组名或指针变量指针变量。此时传递的是数组首个元素的地址。此时传递的是数组首个元素的地址。例例8.11有一个一维数组有一个一维数组score,内放,内放10个学生成绩,求平均成绩。个学生成绩,求平均成绩。float average(float array10) int i;float aver,sum=array0;for(i=1;i10;i+) sum=sum+arra

30、yi;aver=sum/10;return(aver);main( )float score10,aver;int i;printf(“input 10 score:n”);for(i=0;i10;i+) scanf(“%f”,&scorei);printf(“n”);aver=average(score);printf(“average score is %5.2f”,aver);说明:说明:1)用数组名作函数参数,用数组名作函数参数,应该在主调函数和被调应该在主调函数和被调用函数分别定义数组用函数分别定义数组,不能只在一方定义;,不能只在一方定义;2)实参数组与形参数组实参数组与形参数组类

31、型应一致类型应一致,否则出错;,否则出错;3)实参数组与形参数组实参数组与形参数组大小可以一致也可以不一大小可以一致也可以不一致致,C编译对形参数组大小不作检查,编译对形参数组大小不作检查,只是将实参数组只是将实参数组的首地址传给形参数组的首地址传给形参数组;4)形参数组也可以不指定大小,在定义数形参数组也可以不指定大小,在定义数组时在数组名后面跟一个空的方括弧,为了在被组时在数组名后面跟一个空的方括弧,为了在被调用函数中处理数组元素的需要,调用函数中处理数组元素的需要,可以另设一个可以另设一个参数,传递数组元素的个数参数,传递数组元素的个数。参见。参见P180例例8.125)数组名数组名作函

32、数实参,不是值传递而是作函数实参,不是值传递而是地地址传递址传递,实参和形参数组将共占用同一段内存,实参和形参数组将共占用同一段内存单元,如果形参数组中各元素发生变化会使实参单元,如果形参数组中各元素发生变化会使实参数组元素的值同时发生变化数组元素的值同时发生变化。例例8.13用选择法对数组中用选择法对数组中10个整数按由小到达排序。个整数按由小到达排序。选择法介绍:选择法介绍:1)将)将10个数进行相互比较,找出最小数,将之与个数进行相互比较,找出最小数,将之与a0对换;对换;2)再将)再将a1到到a9的数进行比较,找出最小数,将之与的数进行比较,找出最小数,将之与a1对换;对换;3),共比

33、较,共比较9轮,最后得到排序后的结果;轮,最后得到排序后的结果;以以5个数为例说明:个数为例说明:a0a1a2a3a436194未排序时的情况未排序时的情况16394将将5个数中最小数个数中最小数1与与a0对换对换13694将余下的将余下的4个数中最小数个数中最小数3与与a1对换对换13496将余下的将余下的3个数中最小数个数中最小数4与与a2对换对换13469将余下的将余下的2个数中最小数个数中最小数6与与a3对换对换至此完成排序至此完成排序void sort(int array ,int n) int i,j,k,t;for(i=0;in-1;i+) k=i; for(j=i+1;jn;j

34、+) if(arrayjarrayk) k=j; t=arrayk;arrayk=arrayi;arrayi=t; main( ) int a10,i; printf“enter the arrayn”); for(i=0;i10;i+) scanf(“%d”,&ai); sort(a,10); printf(the sorted array:n); for(i=0;ib?a:b;return(c);main()inta=8;printf(“%d”,max(a,b);结果为:结果为:8a,b为全局变量a,b为局部变量形参a,b作用范围局部变量a作用范围全局变量b作用范围8.9变量的存储类别变量

35、的存储类别8.9.1动态存储方式与静态存储方式动态存储方式与静态存储方式按按作用域作用域来分:来分:全局变量和局部变量。全局变量和局部变量。按按变量值生存期变量值生存期来分:静态存储方式、动态存储方式。来分:静态存储方式、动态存储方式。静态存储方式:静态存储方式:在程序运行期间分配固定的存储空间在程序运行期间分配固定的存储空间的方式的方式动态存储方式:动态存储方式:在程序运行期间根据需要进行动态的在程序运行期间根据需要进行动态的分配存储空间的方式分配存储空间的方式。内存中的供用户使用的存储空间的情况。这个存储内存中的供用户使用的存储空间的情况。这个存储空用户区间。分为三部分,见图。空用户区间。

36、分为三部分,见图。程序区程序区静态存储区静态存储区动态存储区动态存储区用户区用户区全局变量全局变量全部全部存放在存放在静态存储区:静态存储区:非动态地进行分配和释放,在非动态地进行分配和释放,在程序开始程序开始执行时给全局执行时给全局变量分配存储区,变量分配存储区,程序执行完毕程序执行完毕就释放。在程序执行过程就释放。在程序执行过程中它们占据固定的存储单元。中它们占据固定的存储单元。动态存储区动态存储区中存放以下数据:中存放以下数据:1.函数形式参数函数形式参数。2.自动变量自动变量(未加(未加static声明的局部声明的局部变量)。变量)。3.函数调用时的现场保护和返回地址函数调用时的现场保

37、护和返回地址等。等。动态地进行分配和释放。在动态地进行分配和释放。在函数调用函数调用开始时分配动态开始时分配动态存储空间,存储空间,函数结束函数结束时释放这些空间。时释放这些空间。在在C语言中每一个语言中每一个变量变量和和函数函数有有两个属性两个属性:数据类型数据类型和和数据存储类别数据存储类别。数据类型包括整型、字符型等。存储类。数据类型包括整型、字符型等。存储类别措的是数据在内存中存储的方法,存储方法分为两大类:别措的是数据在内存中存储的方法,存储方法分为两大类:静态存储类静态存储类和和动态存储类动态存储类。具体包含四种:。具体包含四种:自动的自动的(auto),静态的(静态的(stati

38、c)寄存器的(寄存器的(register),外外部的(部的(extern),根据变量的存储类别,可以知道变量的,根据变量的存储类别,可以知道变量的作用域和生存期。作用域和生存期。8.9.2auto变量变量函数中的局部变量,如不专门声明为函数中的局部变量,如不专门声明为static存储类存储类别,都是动态地分配存储空间的,别,都是动态地分配存储空间的,数据存储在动态存数据存储在动态存储区中在函数调用结束时就自动释放这些存储空间,因储区中在函数调用结束时就自动释放这些存储空间,因此此这类局部变量称为这类局部变量称为自动变量自动变量。自动变量用关键字。自动变量用关键字auto作存储类别的声明。例如:

39、作存储类别的声明。例如:intf(inta) /*定义定义f函数,函数,a为形参为形参*/autointb,c=3/*定义定义b,c为自动变量为自动变量*/实际上,关键字实际上,关键字“auto”可以省略,可以省略,auto不写则隐含不写则隐含确定为确定为“自动存储类别自动存储类别”。程序中大多数变量属于自动。程序中大多数变量属于自动变量。我们前面介绍的函数中定义的变量都没有声明为变量。我们前面介绍的函数中定义的变量都没有声明为auto,其实都隐含指定为自动变量。,其实都隐含指定为自动变量。8.9.3用用static声明局部变量声明局部变量 有时希望有时希望函数中函数中的局部变量的值在的局部变

40、量的值在函数调用结束后函数调用结束后不消失而保留原值不消失而保留原值,即其占用的存储单元不释放,在下,即其占用的存储单元不释放,在下一次该函数调用时,该变量已有值,就是上一次函数调一次该函数调用时,该变量已有值,就是上一次函数调用结束时的值。这时就应该指定该局部变量为用结束时的值。这时就应该指定该局部变量为”静态局部静态局部变量变量”,用关键字,用关键字static。进行声明。进行声明。例例8.17 intf(inta)autointb=0;staticintc=3;b=b+1;c=c+1;return(a+b+c);main()inta=2,i;for(i=0;i3;i+)printf(“%

41、d”,f(a);运行结果为:7 8 9说明:说明:1)静态局部变量属于静态存储类别,在静态存储区内静态局部变量属于静态存储类别,在静态存储区内分配存储单元,在程序整个运行期间都不释放;分配存储单元,在程序整个运行期间都不释放;2)对对静态局部变量静态局部变量是在是在编译时赋初值编译时赋初值的,在程序运行的,在程序运行时它已有初值,以后每次调用函数时不再重新赋初值时它已有初值,以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。而只是保留上次函数调用结束时的值。自动变量赋初值自动变量赋初值,不是在编译时进行,而是,不是在编译时进行,而是在函在函数调用时进行数调用时进行,每调用一次函

42、数重新给一次初值,相,每调用一次函数重新给一次初值,相当于执行一次赋值语句;当于执行一次赋值语句;3)如在定义局部变量时不赋初值的话,对如在定义局部变量时不赋初值的话,对静态局部变静态局部变量量,编译时自动赋初值,编译时自动赋初值0(对数值型变量对数值型变量)或或空字符空字符(对字对字符变量符变量)。而对。而对自动变量自动变量来说,如果不赋初值则它的值来说,如果不赋初值则它的值是一个是一个不确定的值不确定的值。4)虽然静态局部变量在函数调用结束后仍然存在,但其虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的。他函数是不能引用它的。使用局部静态变量一般情况:使用局部静态变量一般

43、情况:(1)需要保留函数上一次调用结束时的值。需要保留函数上一次调用结束时的值。(2)如果初始化后,变量只被引用而不改变其值,如果初始化后,变量只被引用而不改变其值,则这时用静态局部变量比较方便,以免每次调用时重新则这时用静态局部变量比较方便,以免每次调用时重新赋值。赋值。但是应该看到,用静态存储要多占内存,而且降低但是应该看到,用静态存储要多占内存,而且降低了程序的可读性,当调用次数多时往往弄不清静态局部了程序的可读性,当调用次数多时往往弄不清静态局部变量的当前值是什么。因此,如不必要,不要多用静态变量的当前值是什么。因此,如不必要,不要多用静态局部变量。局部变量。8.9.4register

44、变量变量 一般情况下,一般情况下,变量变量(包括静态存储方式和动态存储方式)的值(包括静态存储方式和动态存储方式)的值是是存放在内存中的存放在内存中的,当程,当程序中用到哪一个变量的值时,由控制器发序中用到哪一个变量的值时,由控制器发出指令将内存中该变量的值送到运算器中。经过运算器进行运算,出指令将内存中该变量的值送到运算器中。经过运算器进行运算,如果需要存数,再从运算器将数据送到内存存放。如果需要存数,再从运算器将数据送到内存存放。如果有一些变量使用频繁,则从内存存取数据将花费较多时间。如果有一些变量使用频繁,则从内存存取数据将花费较多时间。为了提高执行效率,为了提高执行效率,C语言允许将局

45、部变量的值放在语言允许将局部变量的值放在CPU中的寄存中的寄存器中器中。由于对寄存器的存取速度远高于对内存的存取速度,因此这。由于对寄存器的存取速度远高于对内存的存取速度,因此这样就可以提高执行效率。这种变量叫做样就可以提高执行效率。这种变量叫做”寄存器变量寄存器变量”,用关键字,用关键字register作声明作声明,内存CPU总线运算器 控制器寄存器例例8.19使用寄存器变量使用寄存器变量intfac(intn)registerinti,f=1;for(i=1;i=n;i+)f=f*i;return(f);main()inti;for(i=1;i=5;i+)printf(“%d!=%dn”,

46、i,fac(i);说明:说明:1))只有只有局部自动变量局部自动变量和和形式参数形式参数可以作为寄存器变量,可以作为寄存器变量,其他(如全局变量)不行。其他(如全局变量)不行。2)一个计算机系统中的寄存器一个计算机系统中的寄存器数目是有限数目是有限的,不能定义的,不能定义任意多个寄存器变量。任意多个寄存器变量。3)不同的系统对寄存器变量的处理方法是不同的,有的不同的系统对寄存器变量的处理方法是不同的,有的系统对寄存器当自动变量处理,分配内存单元,有的系系统对寄存器当自动变量处理,分配内存单元,有的系统只允许将统只允许将int,char和指针型变量定义为寄存器变量;和指针型变量定义为寄存器变量;

47、当今的优化编译系统能够识别使用频繁的变量,从当今的优化编译系统能够识别使用频繁的变量,从而自动地将这些变量放在寄存器中,而不需要程序设计而自动地将这些变量放在寄存器中,而不需要程序设计者指定;者指定;4)局部静态变量局部静态变量不能定义为不能定义为寄存器变量寄存器变量。8.9.5用用extern声明外部变量声明外部变量外部变量(即全局变量)外部变量(即全局变量)是在函数的外部定义的,是在函数的外部定义的,它的作用域为从它的作用域为从变量的定义处开始,到本程序文件的未变量的定义处开始,到本程序文件的未尾。在此作用域内,全局变量可以为程序中各个函数所尾。在此作用域内,全局变量可以为程序中各个函数所

48、引用。编译时,将外部变量分配在静态存储区。引用。编译时,将外部变量分配在静态存储区。有时需要用有时需要用extern来声明外部变量,以来声明外部变量,以扩展外部变量扩展外部变量的作用域的作用域.1.在一个文件内声明外部变量在一个文件内声明外部变量如果外部变量不在文件的开头定义,其如果外部变量不在文件的开头定义,其有效的作用范有效的作用范围只限于定义处到文件终了围只限于定义处到文件终了。如果在定义点之前的函数。如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字想引用该外部变量,则应该在引用之前用关键字extern对对该变量作该变量作“外部变量声明外部变量声明”。表示该变量是一个已经

49、定义。表示该变量是一个已经定义的外部变量。有了此声明,就可以的外部变量。有了此声明,就可以从从“声明声明”处开始,合处开始,合法使用该外部变量法使用该外部变量。2.在多文件的程序中声明外部变量在多文件的程序中声明外部变量一个一个C程序可以由一个或多个源程序文件组成。如程序可以由一个或多个源程序文件组成。如果程序只由一个源文件组成,使用外部变量的方法如前果程序只由一个源文件组成,使用外部变量的方法如前面介绍。面介绍。如果一个程序包含两个文件,在两个文件中都要用如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量,不能分别在两个文件中对该变量各到同一个外部变量,不能分别在两个文件中对该变量

50、各自定义,否则进行程序的连接时会出现自定义,否则进行程序的连接时会出现“重复定义重复定义”的错的错误。正确的做法是:误。正确的做法是:在任一个文件中定义该变量,而在在任一个文件中定义该变量,而在另一文件中用另一文件中用extern对该变量作对该变量作“外部变量声明外部变量声明”在编译在编译和连接时系统会由此知道此变量是一个已在别处定义的和连接时系统会由此知道此变量是一个已在别处定义的外部变量,并将在另一文件中定义的外部变量的作用域外部变量,并将在另一文件中定义的外部变量的作用域扩展到本文件扩展到本文件,在本文件中可以合法地引用外部变量。,在本文件中可以合法地引用外部变量。例例8.21给定给定b

51、的值,输入的值,输入a和和m,求,求a*b和和am的值。的值。文件文件file1.c中的内容:中的内容:int A; /*定义外部变量*/main( ) input power(int);/*对调用函数作声明*/int b=3,c,d,m;printf(“enter the number a and its power m:n”);scanf(“%d,%d”,&a,&m);c=A*b;printf(“%d*%d=%dn”,A,b,c);d=power(m);printf(“%d*%d=%d”,A,m,d);文件文件file2.c中的内容:中的内容:extern A; /*声明A为一个已定义的外

52、部变量*/power(int n); int i,y=1;for(i=1;i=n;i+)y=y*A;return(y);说明:说明:1)假如程序有假如程序有5个源文件,在一个文件中定义外部个源文件,在一个文件中定义外部整型变量整型变量A,其他,其他4个文件都可以引用个文件都可以引用A,但必须在每一,但必须在每一个文件中都加上一个个文件中都加上一个externA声明。在各文件经过编译声明。在各文件经过编译后,将各目标文件链接成一个可执行的目标文件;后,将各目标文件链接成一个可执行的目标文件;2)在编译时遇到在编译时遇到extern时,先在本文件中找外部变时,先在本文件中找外部变量的定义,如果找到

53、,就在本文件中扩展作用域,如果量的定义,如果找到,就在本文件中扩展作用域,如果找不到,就在链接时从其他文件中找外部变量的定义,找不到,就在链接时从其他文件中找外部变量的定义,如果找到,就将作用域扩展到本文件。如果找不到,按如果找到,就将作用域扩展到本文件。如果找不到,按出错处理。出错处理。8.9.6用用static声明外部变量声明外部变量有时在程序设计中希望有时在程序设计中希望某些外部变量只限于被本文某些外部变量只限于被本文件引用,而不能被其他文件引用件引用,而不能被其他文件引用。这时可以在定义外部。这时可以在定义外部变量时加一个变量时加一个static声明。声明。这种加上这种加上static

54、声明,只能用于本文件的外部变量声明,只能用于本文件的外部变量(全局变量)称为静态外部变量。这为程序的模块化、(全局变量)称为静态外部变量。这为程序的模块化、通用性提供方便。如果已知道其他文件不引用本文件的通用性提供方便。如果已知道其他文件不引用本文件的外部变量,可以对本文件中的外部变量都加上外部变量,可以对本文件中的外部变量都加上static,成,成为静态外部变量,以免彼其他文件误用。为静态外部变量,以免彼其他文件误用。需要指出对外部变量加上需要指出对外部变量加上static声明,并不意味着这声明,并不意味着这时才是静态存储(存放在静态存储区中),而不是时才是静态存储(存放在静态存储区中),而

55、不是static的是动态存储(存放在动态存储区)。两种形式的外部的是动态存储(存放在动态存储区)。两种形式的外部变量都是静态存储方式,只是作用范围不同而已,都是变量都是静态存储方式,只是作用范围不同而已,都是在编译时分配内存的。在编译时分配内存的。8.10内部函数和外部函数内部函数和外部函数 函数本质上是全局的函数本质上是全局的,因为一个函数要被另外函数,因为一个函数要被另外函数调用。但是,也可以指定函数不能被其他文件调用。根调用。但是,也可以指定函数不能被其他文件调用。根据据函数能否被其他源文件调用函数能否被其他源文件调用,将函数区分为,将函数区分为内部函数内部函数和和外部函数外部函数。8.

56、10.1内部函数内部函数如果一个函数只能被本文件中其他函数所调用,它如果一个函数只能被本文件中其他函数所调用,它称为内部函数称为内部函数。在定义内部函数时,在函数名和函数类。在定义内部函数时,在函数名和函数类型的前面加型的前面加static。即。即static类型标识符类型标识符函数名函数名(形参表形参表)例如:例如:staticintfun(inta,intb)内部函数义称内部函数义称静态函数静态函数。使用内部函数,可以使函数。使用内部函数,可以使函数只局限于所在文件,如果在不同的文件中有同名的内部只局限于所在文件,如果在不同的文件中有同名的内部函数,互不干扰,这样不同的人可以分别编写不同的

57、函函数,互不干扰,这样不同的人可以分别编写不同的函数,而不必担心所用函数是否会与其他文件中函数同名。数,而不必担心所用函数是否会与其他文件中函数同名。8.10.2外部函数外部函数在定义函数时,如果在函数首部的在定义函数时,如果在函数首部的最左端冠以关键最左端冠以关键字字extern,则表示此函数是,则表示此函数是外部函数外部函数,可供其他文件调用。,可供其他文件调用。如函数首部可以写为如函数首部可以写为externintfun(inta,intb)这样,函数这样,函数fun就可以为其他文件调用。就可以为其他文件调用。C语言规定,语言规定,如果在定义函数时省略如果在定义函数时省略extern,则

58、隐含为外部函数。本书,则隐含为外部函数。本书前面所用的函数都是外部函数。前面所用的函数都是外部函数。利用利用函数原形函数原形也能够把函数的作用域扩展到定义该也能够把函数的作用域扩展到定义该函数的文件之外而不使用函数的文件之外而不使用extern。只要在使用该函数的每。只要在使用该函数的每一个文件中包含该函数的函数原型即可。最常用的方法一个文件中包含该函数的函数原型即可。最常用的方法是使用是使用#include命令命令。8.11在在TurboC中运行一个多文件程序中运行一个多文件程序设有一个程序,包含设有一个程序,包含4个文件:个文件:file1.c,file2.c,file3.c,file4.

59、c。步骤:。步骤:1)先后输入编辑先后输入编辑4个文件,并分别以文件名个文件,并分别以文件名file1.c,file2.c,file3.c,file4.c,存储在磁盘上。,存储在磁盘上。2)建立一个建立一个“项目文件项目文件”,它不包括任何程序语句,而,它不包括任何程序语句,而只包括组成程序的所有的文件名。即只包括组成程序的所有的文件名。即file1.cfile2.cfile3.cfile4.c扩展名扩展名.C可以省写。可以省写。4个文件顺序任意。可以连续写在个文件顺序任意。可以连续写在同一行上,如:同一行上,如:file3fllelfile2file4如果这些源文件不在当前目录下,应指出路径

60、。如果这些源文件不在当前目录下,应指出路径。4)将以上内容存盘,文件名自定,但扩展名必须为将以上内容存盘,文件名自定,但扩展名必须为.prj(表示为(表示为project文件)。设文件名为文件)。设文件名为a.prj。在。在TurboC主主菜单中选择菜单中选择project菜单,按回车键后出现下拉菜单,找到其菜单,按回车键后出现下拉菜单,找到其中的中的Pprojectname项并按回车键,输入项目文件名项并按回车键,输入项目文件名a.prj以以代替代替*.prj,表示当前准备编译的是,表示当前准备编译的是a.prj中包括的文件。中包括的文件。5)进行编译连接,系统先后将进行编译连接,系统先后将

61、4个文件翻译成目标文件,个文件翻译成目标文件,把它们连接或一个可执行文件把它们连接或一个可执行文件a.exe(文件名主于与项目文件(文件名主于与项目文件相同)。相同)。6)按按CtrlF9键,即可运行可执行文件键,即可运行可执行文件a.exe。用用#include命令命令将将file2.c、file3.c和和file4.c包含到包含到file1.c中。在中。在file1.c中中的开头加的开头加3行:行:#include“file2.c”#include“file3.c”#include“file4.c”这时,在编译时,系统自动将这这时,在编译时,系统自动将这3个文件放到个文件放到main函函数的前头,作为一个整体编译,而不是分数的前头,作为一个整体编译,而不是分4个文件编译。个文件编译。这时,这些函数被认为是在同一文件中,不再是作为外这时,这些函数被认为是在同一文件中,不再是作为外部函数被其他文件调用了。部函数被其他文件调用了。main函数中原有的函数中原有的extern声明声明可以不要。可以不要。

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 建筑/环境 > 施工组织

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号