收藏 分销(赏)

C语言-函数.ppt

上传人:仙人****88 文档编号:14189372 上传时间:2026-07-08 格式:PPT 页数:95 大小:360KB 下载积分:10 金币
下载 相关
C语言-函数.ppt_第1页
第1页 / 共95页
C语言-函数.ppt_第2页
第2页 / 共95页


点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第六章 函数,教学要求,1,、理解函数的功能。,2,、掌握函数定义的一般形式。,3,、掌握函数的形参与实参的对应关系、参数传递方法及函数返回值的概念。,4,、掌握函数调用的几种形式。,5,、掌握函数嵌套调用的一般过程。,6,、了解函数递归调用的几种形式。,7,、掌握数组名作为函数的参数的一些特点。,8,、掌握局部变量与全局变量的概念及它们的使用特点。,9,、掌握动态存储变量与静态存储变量的含义,会正确识别和使用。,10,、了解内部函数与外部函数的含义。,一、,函数的定义,二、,函数的调用,1,、,函数的一般调用,2,、,函数的嵌套调用,3,、,函数的递归调用,三、,数组作为函数的参数,四、,局部变量与全局变量,五、,变量的动态存储与静态存储,六、,内部函数与外部函数,本章教学要点,函数的定义,1,、,概述,2,、,函数定义的方法,3,、,函数的参数,4,、,函数的返回值,概述,1,、含义:一个较大的程序可分为若干个程序模块,每一个模块用来实现一个特定的功能。,C,语言中,函数是完成一个独立功能的程序代码。一个,C,程序可由一个主函数和若干个函数构成。由主函数调用其它函数,其它函数也可以互相调用。,2,、,C,程序的基本结构(,如图,):,3,、,例:,4,、,要点,:,例,exp6_1:,函数的结构,main(),printstar,();,print_message();,printstar,();,printstar,(),printf,(“*”);,print_message(),printf,(“how do you do!n”);,对函数的理解,:,一个源程序由一个或多个函数组成。以源文件为单位进行编译。,一个,c,程序由一个或多个源程序组成。,c,程序的执行顺序从,main(),开始,调用其他函数后,流程回到,main(),函数。,c,程序的所有的函数都是平行的,不存在函数的嵌套定义,可以互相调用。,从用户的角度对函数的分类:,(1),标准库函数:由系统提供,用户可以直接使用它们。,(2),用户自定义函数:解决用户的专门需要。,从函数的形参对函数的分类:,(1),无参数函数:主调函数并不将数据传送给被调用函数,一般用于执行指定的一组操作,可以带回或不带回函数值。,(2),有参数函数:主调函数可以将数据传给被调函数使用,被调函数中的数据也可以带回给主调函数使用。,函数定义的方法,1,、无参数函数的定义,函数类型说明符函数名,(),如:,printstar,(),函数说明部分;,printf,(“*n”);,语句块;,2,、有参数函数的定义,函数类型说明符函数名,(,形式参数表,),形参说明,如:,int,add(x,,,y),函数说明部分;,int,x,,,y;,语句块;,return x+y;,3,、,例:,4,、,要点:,函数类型 函数名,(,数据类型 参数,,数据类型 参数,2),说明语句部分;,int,add(,int,x,int,y),可执行语句部分;,int,z;z=x+y;return(z);,例,exp6_2:,函数的定义,main(),int,a,,,b,,,c;,scanf,(“%d,,,%d”,,,&a,,,c=,max(a,,,b);,printf,(“max=%d”,,,c);,int,max(,int,x,,,int,y),int,z;,z=xy?x:y;,return(z);,要点:,1,、函数的类型:即函数返回值的类型,(,缺省时为整型)。若不返回任何值,则应将其类型定义为,v,oid,。,2,、,函数名的定义:,规则:按,“,见名知意,”,表示法。,含义:函数名代表此函数在内存中的起始位置,。,3,、形参的定义:,形参的个数和类型均由函数的功能来决定。,4,、空函数的定义,既无参数、函数体又为空的函数。其一般形式为:,函数类型,函数名,(,void),函数的参数,函数的参数分为,形参,和,实参,两种,作用是实现数据传送。,形参出现在函数定义中,只能在该函数体内使用。发生函数调用时,调用函数把实参的值复制,1,份,传送给被调用函数的形参,从而实现调用函数向被调用函数的数据传送。,实参对形参的数据传递,。,1,、形式参数,写在函数定义中函数名后面括号中的,变量,叫做“形式参数”,2,、实际参数,出现在函数调用时,函数名后面括号中的,表达式,称为“实际参数”。,例:,3,、要点,:,形参变量只有在函数被调用时才占用内存空间,调用结束后所占空间即被释放,;,形参只有在该函数内有效。调用结束,返回调用函数后,则不能再使用该形参变量。,在函数定义时必须指出形参的类型,;,实参与形参的类型必须一致,;,实参可以是常量,变量或表达式,;,实参对形参的传递数据是单向传递,(,值传递),;,即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。,实参和形参占用不同的内存单元,即使同名也互不影响。,void main(),void s(,int,n);/*,说明函数*,/,int,n=100;/*,定义实参,n,,,并初始化*,/,s(n);/*,调用函数*,/,printf,(n_s=%dn,n);/*,输出调用后实参的值,便于进行比较*,/,getch,();,/*/,void s(,int,n),int,i;,printf,(n_x=%dn,n);/*,输出改变前形参的值*,/,for(i=n-1;i=1;i-)n=n+i;/*,改变形参的值*,/,printf,(n_x=%dn,n);/*,输出改变后形参的值*,/,1,、函数的返回值是通过函数中的,return,语句来完成的,,return,语句一次只能返回一个值,;,return,语句的一般格式:,return(,返回值表达式,);,2,、由,return,语句返回的数据类型应与函数定义时的类型一致。,例:,3,、当在函数的定义时,未指出函数的类型,,c,语言默认的类型为整型。,4,、函数没有,return,语句并不表明函数没有返回值,只是这个返回值对于调用者来说可能是没有用的,这个返回值随函数的不同它的值也不尽相同。,5,、如果我们明确表示函数不能返回值,在函数的定义时用“,void”,加以说明,这样可以确保函数不带回返回值。,6,、,例:,函数的返回值,例,exp6_4:,对函数返回值的理解:,main(),int,a,,,b,,,c;,a=,printstar,();,b=print_message();,c=,printstar,();,printf,(“%d,,,%d,,,%dn”,,,a,,,b,,,c);,若不需要函数带回任何值,可使用:,void,printstar,(),void print_message(),例,exp6_3:,函数返回值的类型与其定义的类型不符时:,main(),float a,,,b;,int,c;,scanf,(“%f,,,%f”,,,&a,,,c=max(a,,,b);,printf,(“max is%dn”,,,c);,max(float x,,,float y),输入:,1.5,,,2.5,float z;,输出:,max is 2,z=xy?x:y;return(z);,函数的一般调用,1,、函数调用的一般形式:,函数名,(,实参表列,);,如:,add(,int,x,,,int,y),的调用为,add(2,,,3),2,、,函数调用的方式,3,、函数调用的规则:,调用函数时,函数名称必须与具有该功能的自定义函数名称完全一致,实参与形参在个数与类型上必须保持一致。,当函数无参数时,实参表列就为空,但括号不能少。,实参表列中的各个参数之间用逗号隔开。,实参与形参是一 一对应的关系(函数调用的过程)。,对于实参表的求值顺序各个系统是不一致的。,如:,4,、,函数的引用性说明,1,、函数语句:,功能:将函数调用作为一个语句。,如:,printf,(“book”);,要点:,不要求函数带回值,只要求完成一定的操作。,2,、函数表达式:,功能:将函数作为表达式的一部分。,如:,c=2*max(a,,,b);,要点:,要求函数带回一个确定的值,以参加表达式的运算。,3,、一个函数作为另一个函数的参数:,功能:将函数的调用作为一个函数的实参。,如:,m=,max(a,,,max(b,,,c),);,要点:其实质也是函数表达式的调用。,函数调用的方式,1,、被调用函数必须是一个已经存在的函数。,2,、如果使用库函数应在文件头加上,#,include,命令,以便将有关的库函数包含到本源文件中来。,3,、对于用户自定义函数,函数的定义部分应出现在该函数被调用之前。不然的话,在调用函数之前应作声明。,4,、引用性说明的方法:,返回值类型 函数名(),如,:,int,add();,采用函数原型方式,:,函数类型 函数名,(,数据类型,参数名,数据类型,参数名,2),;,5,、,举例,:,函数的引用性说明,例,exp6_5:,函数的引用性说明:,main(),float add();,float add(x,,,y),float a,,,b,c;float x,,,y;,float z;,scanf,(“%f,,,%f”,,,&a,,,c=add(a,,,b);return(z);,printf,(“sum is%fn”,,,c);,输入:3,.6,,,5.5,输出:,sum is 9.10000,例,exp6_6,:,实参表求值顺序的一致,Main(),int,f(,int,a,,,int,b),int,i=2,,,p;,int,c;,p=f(i,,,+i);if(ab)c=1;,printf,(“%d”,,,p);else if(a=b)c=0;,else c=-1;,return c;,改进,的做法:,j=i;k=+i;,或,j=+i;,p=(j,,,k)p=f(j,,,j),1,、,含义:所谓函数的嵌套调用是指一个函数在被调用时其本身又调用了其他函数。,2,、嵌套调用的过程:,3,、,举例:,函数的嵌套调用,例,exp6_7:,函数的嵌套调用,swap(,int,a,,,int,b),int,t;,t=a,,,a=b,,,b=t;,printf,(“%d,,,%d”,,,a,,,b);/,嵌套调用,main(),int,a=3,,,b=5;,swap(a,,,b);/,调用,printf,(“%d,,,%d”,,,a,,,b);,例,exp6_14:,计算,s=1,k,+2,k,+3,k,+,N,k,/*,功能:函数的嵌套调用*,/,#,define K 4,#define N 5,long f1(,int,n,int,k)/*,计算,n,的,k,次方*,/,long power=n;,int,i;,for(i=1;ik;i+)power*=n;,return power;,long f2(,int,n,int,k)/*,计算,1,到,n,的,k,次方之累加和*,/,long sum=0;,int,i;,for(i=1;i1),age(n)=,递归调用的过程,age(5)=,age(4)+,2,age(4)=,age(3)+,2,age(3)=,age(2)+,2,age(2)=,age(1)+,2,age(1)=,10,age(2)=,10+,2,age(3)=,12+,2,age(4)=,14+,2,age(5)=,16+,2,程序代码:,age(,int,n),int,c;,if(n=1)c=10;,else c=age(n-1)+2;,printf,(“%,dage,is%dn”,,,n,,,c);,return c;,main(),age(5);,运行结果为,:,1 age is 10,2 age is 12,3 age is 14,4 age is 16,5 age is 18,例,exp6_11:,用递归的方法求,n!,float,fac,(,int,n),float f;,if(n0),printf,(“n1),例,exp6_12:,求下面程序的输出结果。,fun(,int,k),if,(,k=0)return 3;,return(fun(k-1)*3);,main(),int,w=10;,printf,(“%dn”,,,fun(5)*w);,运行结果为:,729,例,6.13,Hanoi(,汉诺,),塔问题。,古代有一个梵塔,塔内有,3,个座,A,、,B,、,C,,,开始,A,座上有,64,个盘子,盘子大小不等,小的在上,(,如图,),有一个老和尚想把这,64,个盘子从,A,座移到,C,座,但每次只允许移动一个盘,且在移动过程中在,3,个座上都始终保持大盘在下,小盘在上,在移动过程中可以利用,B,座,要求编程打印出移动的步骤。,A,B,C,问题的分析:,(,1,)要想把,64,个盘子移到,C,座,上,可以先把,63,个盘子借助于,C,座移动到,B,座上,然后再把第,64,个盘子移动到,C,座,上。,(,2,)要想把,63,个盘子移到,C,座上,可以先把,62,个盘子借助于,C,座移动到,A,座上,然后再把第,63,个盘子移动到,C,座上。,这属于一个递归的问题。需要,2,64,-1,个步骤才能完成,A,C,的移动。,将,n,个盘子从,A,针,移到,C,针可以分解为以下三个步骤:,1,、将,A,上,n-1,个盘借助,C,针先移到,B,针上。,2,、把,A,针上剩下的一个盘移到,C,针上。,3,、将,n-1,个盘从,B,针借助于,A,针移到,C,针上。,例如:要想将,A,针上,3,个盘子移动到,C,针上,可以分解为以下三步:,1,、将,A,上,2,个盘借助,C,针先移到,B,针上。,2,、把,A,针上,1,个盘移到,C,针上。,3,、将,2,个盘从,B,针借助于,A,针移到,C,针上。,A,B,C,例如将,A,针上,3,个盘子移动到,C,针上,A,B,C,1.1,将,A,针上,1,个盘子从,A,移动到,C,A,B,C,1.2,将,A,针上,1,个盘子从,A,移动到,B,A,B,C,1.3,将,C,针上,1,个盘子从,C,移动到,B,A,B,C,2,将,A,针上,1,个盘子从,A,移动到,C,A,B,C,3.1,将,B,针上,1,个盘子从,B,移动到,A,A,B,C,3.2,将,B,针上,1,个盘子从,B,移动到,C,A,B,C,3.3,将,A,针上,1,个盘子从,A,移动到,C,将,以上综合起来,可得到移动的步骤为:,A,C,A,B,C,B,A,C,B,A,B,C,A,C.,1.1,1.2,1.3,和,3.1,3.2,3.3,,都是把,n-1,个盘从一个针移动到另一个针上,采取的办法是一样的,只是针的名字不同而已。为使之一般化,可以表示为:,将“,one”,针上,n-1,个盘移动到“,two”,针,借助“,three”,针。,只是分别对应的是:,oneA,twoB,threeC,oneB,twoC,threeA,因此,可以将上面三个步骤分成两类操作。,1,、将,n-1,个盘从一个针移动到另一个针上(,n1,)。,2,、,将,1,个盘子从一个针上移动到另一个针上。,可以用两个函数实现上述两类操作。,程序实现,(三个盘子的情况),/*,将,1,个盘子从一个针上移动到另一 个针上*,/,void move(char x,char y),ptintf,(“%c,%cn”,x,y);,/*,将,n,个盘从,one,借助,two,,,移动到,three*/,void,hanoi,(,int,n,char one,char two,char three),if(n=1)move(one,three),else,hanoi,(n-1,one,three,two);,move(one,three);,hanoi,(n-1,two,one,three);,main(),int,m;,printf,(“input the number of,diskes,:”),;,scanf,(“%d”,printf,(“the step to moving%3d,diskes,:n”,m);,hanoi,(m,A,B,C);,数组作为函数的参数,数组元素作为函数的实参,:“值传送”的含义与用法。,数组名作为函数的参数(形参和实参),:“地址传送”的要点。,二维数组作为函数的参数,数组元素作函数的参数,数组元素就是下标变量,它与普通变量并无区别。数组元素只能用作函数实参,其用法与普通变量完全相同:在发生函数调用时,把数组元素的值传送给形参,实现单向值传送,。,例如,:,fun(,int,x),x+=3;,main(),int,a10=1,,,2,,,3,,,4,,,5,,,6,,,7,,,8,,,9,,,10,,,i,,,j;,for(i=0;i=a&c=A&c=Z),return(1);,else return(0);,main(),int,i,num=0;,char,str,255;,printf,(Input a string:);,gets(,str,);,for(i=0;,str,i!=0;i+),if(,isalp,(,str,i)num+;,puts(,str,);,printf,(num=%dn,num);,getch,();,说明:,(,1,)用数组元素作实参时,只要数组类型和函数的形参类型一致即可,并不要求函数的形参也是下标变量。换句话说,对数组元素的处理是按普通变量对待的。,(,2,)在普通变量或下标变量作函数参数时,形参变量和实参变量是由编译系统分配的两个不同的内存单元。在函数调用时发生的值传送,是把实参变量的值赋予形参变量。,数组名作函数参数时,既可以作形参,也可以作实参。数组名作函数参数时,要求形参和相对应的实参都必须是类型相同的数组(或指向数组的指针变量),都必须有明确的数组说明,例如,:#,include,fun(char s),int,x=0,,,y;char c;,for(y=,strlen,(s)-1;xy;x+,,,y-),c=sx;sx=sy;sy=c;,main(),char a=“,abcdefgh,”;,fun(a);puts(a);,hgfedcba,数组名作为函数的参数,Exp6_16:,已知某个学生,5,门课程的成绩,求平均成绩。,float aver(float a)/*,求平均值函数*,/,int,i,;,float,av,s=a0,;,for(i=1,;,i5,;,i+)s+=ai,;,av,=s/5,;,return,av,;,void main(),float,sco,5,av,;,int,i,;,printf,(,ninput,5 scores:n),;,for(i=0,;,i5,;,i+),scanf,(%f,&,sco,i),;,av,=aver(,sco,),;,/*,调用函数,实参为一数组名*,/,printf,(average score is%5.2fn,av,),;,getch,();,1.,数组名作为函数的参数,应在调用函数和被 调用函数中分别定义数组,形参与实参的类型应一致。,2,实参与形参的数组的大小可以一致也可以 不一致,形参接收的是实参传来的数组的首地址,对数组的大小不作检查。,如果指定形参数组的大小,则实参数组的大小必须大于等于形参数组,否则因形参数组的部分元素没有确定值而导致计算结果错误,.,4.,数组名作函数的参数传递时,不再是值传递,而是地址传递,实参传递给形参的不是一个简单的数值,而是一段内存单元的首地址,在 被调用函数中对这段地址所指向的单元的内容改变时,将反映到调用函数中。,说明,:,【,例如,】,用选择法对数组中的,10,个数进行排序。,选择法的解题思路,:,(1),将,10,个数中的所有数逐个进行比较找出 其中的最小数,将这个最小数与,10,个数中 的,a0,进行交换,;,(2),将剩下的,9,个数中的所有数逐个进行比较 找出其中的最小数,将这个最小数与,9,个数 中的,a1,进行交换,;,(3),以此类推。,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+),if(arrayjarrayk)k=j;,if(k!=i)t=arrayk,arrayk=arrayi,arrayi=t;,main(),int,a10;,printf,(“,entre,the arrayn”);,for(i=0;i10;i+),scanf,(“%d”,,,sort(a,,,10);,printf,(“the sorted array:n”);,for(i=0;i10;i+),printf,(“%d”,,,ai);,printf,(“n”);,二维(多维)数组作函数参数,多维数组名也可以作函数的参数,从调用函数到被调用函数依然传递的是地址,形参中的数组定义可以省略第一维的大小说明,但第二维的说明不可少。,例如,:,有一个,3*4,的矩阵,求出其中的最大元素的值。,max_value(,int,array34),int,i,,,j,,,max=array00;,for(i=0;i3;i+),for(j=0;j max)max=arrayij;return max;,main(),static,int,a34=1,,,3,,,5,,,7,,,2,,,4,,,6,,,8,,,15,,,17,,,34,,,12;,printf,(“max value is%dn”,,,max_value(a);,局部变量与全局变量,局部变量的含义、应用与使用要点,全局变量的含义、应用与使用要点,语言中所有的变量都有自己的作用域。变量说明的位置不同,其作用域也不同,据此将语言中的变量分为局部变量(内部变量)和全局变量(外部变量)。,局部变量,定义,:,局部变量是在一个函数内部定义的变量,它的有效范围是它被定义的函数范围内,局部变量在其有效范围外是没有意义的。,int,max(,int,a,,,int,b),int,t;,fun(),int,i;,a,,,b,,,t,有效,i,有效,main(),int,a,,,b;,说明,:,(1),主函数,main(),中定义的内部变量,也只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的内部变量。因为主函数也是一个函数,与其它函数是平行关系。这一点是与其它语言不同的,应予以注意。,(2),不同的函数中可以使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。,a,b,有效,(3),形参变量也是内部变量,属于被调用函数;实参变量,则是调用函数的内部变量。,(4),在一个函数内部可以,使用复合语句来定义变量,,这样的变量只在本复合语句中有效。,main(),int,a,b;,int,c;,c=a+b;,C,在此范围内有效,a,、,b,在此范围有效,全局变量,C,语言程序的编译单位是源文件,一个源文件可以包含一个或几个函数。在一个函数内部定义的变量是局部变量,在所有的函数之外定义的变量称为外部变量(或叫做全局变量)。以此类推,在函数外部定义的数组就称为外部数组。,全局变量的有效范围是从变量定义的位置开始,直到本源文件的结束,全局变量可以被本源文件的所有函数共享。,(1),全局变量的设置增强了函数间数据的联系。一 个函数对全局变量的值的改变将会影响到其他 的函数中。,(2),建议在只有必要时才设置全局变量。,int,p=1,,,q=1;/*,定义全局变量,p,,,q*/,float f1(a)/*,定义函数,f1*/,int,a;,int,b,,,c;,char c1,,,c2;/*,定义外部变量,c1,,,c2*/,char f2(,int,x,,,int,y)/*,定义函数,f2*/,int,i,,,j;,main(),int,m,,,n;,全局变量,p,、,q,的有效范围,全局变量,c1,,,c2,的有,效范围,(,3),全局变量在文件的开头定义,则它的有效范围是整个源文 件,但如果全局变量不是在开头定义的,则它有效范围是 从定义点到源文件的结束。,如果想在全局变量的定义点之 前引用时,需要用关键字“,extern”,作提前引用说明。,外部变量说明的一般形式为:,extern,数据类型 外部变量,,外部变量,2,;,注意,:外部变量的定义和外部变量的说明是两回事。外部变量的定义,必须在所有的函数之外,且只能定义一次。而外部变量的说明,出现在要使用该外部变量的函数内,而且可以出现多次。,(4),当全局变量名与局部变量名相同时,则在局部变量的有效 范围内全局变量将被屏蔽而不起作用。,【,例,1】,分析下面的程序写出结果,:,plus(,int,x,,,int,y),;,int,z;z=x+y+:return z;,main()extern,int,a,,,b;,int,z;z=plus(a,,,b);,printf,(“%dn”,,,z);,int,a=13,,,b=-8,,,z=10;,5,举例,2,#,include,f1(,int,x,,,int,y),int,z;return z=xy?x:y;,f2(,int,x,,,int,y),int,z;z=xy?x+:+y;,return z;,main()extern,int,a,,,b;,printf,(“%d,,,%d,,,%dn”,,,a,,,b,,,f1(a,,,b);,printf,(“%d,,,%d,,,%dn”,,,a,,,b,,,f2(a,,,b);,int,a=20,,,b=-15;/*20,,,-15,,,20,举例,3,:输入长方体的长(,l,)、,宽(,w,)、,高(,h,),,求长方体体积及正、侧、顶三个面的面积。,/*,功能:利用全局变量计算长方体的体积及三个面的面积*,/,int,s1,s2,s3;,int vs,(,int,a,int,b,int,c),int,v;,v=a*b*c;s1=a*b;s2=b*c;s3=a*c;,return v;,main(),int,v,l,w,h;,clrscr,();,printf,(,ninput,length,width and height,:,);,scanf,(%d%d%d,v=,vs,(l,w,h);,printf,(v=%d s1=%d s2=%d s3=%dn,v,s1,s2,s3);,getch,();,举例,4,:,外部变量的定义与说明。,int vs,(,int xl,int xw,),extern,int xh,;,/*,外部变量,xh,的说明*,/,int,v,;,v=,xl,*,xw,*,xh,;,/*,直接使用外部变量,xh,的值*,/,return v,;,main(),extern,int xw,xh,;,/*,外部变量的说明*,/,int xl,=5,;,/*,内部变量的定义*,/,printf,(,xl,=%d,xw,=%d,xh,=%d,nv,=%d,xl,xw,xh,vs,(,xl,xw,),;,int xl,=3,xw,=4,xh,=5,;,/*,外部变量,xl,、,xw,、,xh,的定义*,/,5,,,4,,,5,,,100,动态存储与静态存储变量,变量的存储类别,局部变量的存储方式,全局变量的存储方式,:含义与引用方法。,不同存储类别变量的作用域与生存期的特点,变量的存储类别,内存中用户区的划分,:,程序区,静态存储区,动态存储区。如图,:,程序区,静态存储区,动态存储区,1.,程序区存放程序的代码,;,2.,静态存储区存放全局变量和静态的局部变量,;,3.,动态存储区存放函数的局部变量,函数的形参变 量,函数调用时的现场保护和返回地址,;,存放在静态存储区中的变量的生存周期是程序的整个执行过程,;,存放在动态存储区中的变量的生存周期是函数的执行期间。,在,c,语言中将变量和函数的属性划分为两个,:,数据类型和数据的存储类别。存储类别是指数据在内存中的存储方式,共有四种存储类别,:,自动的,(,auto),,,静态的,(,static),,,寄存器的,(,register),,,外部的,(,extern,),,,分别放在,静态存储区,和,动态存储区,。,局部变量的存储方式,一、动态存储,自动局部变量(又称自动变量),定义格式,:,auto,数据类型 变量表,;,函数中定义的变量不作特殊说明都为局部变量,存储在动态存储区,有时可以省略,auto,关键字,当函数调用结束后,它们所占用的存储空间即被释放。例如,:,int,f(a),int,a;,auto,int,b=0,,,c=10;,存储特点,:,1,)自动变量属于动态存储方式。在函数中定义的自动变量,只在该函数内有效;函数被调用时分配存储空间,调用结束就释放。,在复合语句中定义的自动变量,只在该复合语句中有效;退出复合语句后,也不能再使用,否则将引起错误。,2,)定义而不初始化,则其值是不确定的。如果初始化,则赋初值操作是在调用时进行的,且每次调用都要重新赋一次初值。,3,)由于自动变量的作用域和生存期,都局限于定义它的个体内(函数或复合语句),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量,也可与该函数内部的复合语句中定义的自动变量同名。,建议:,系统不会混淆,并不意味着人也不会混淆,所以尽量少用同名自动变量!,二、静态存储静态内部变量,定义格式:,static,数据类型 内部变量表;,存储特点,1,)静态内部变量属于静态存储。在程序执行过程中,即使所在函数调用结束也不释放。换句话说,在程序执行期间,静态内部变量始终存在,但其它函数是不能引用它们的。,2,)定义但不初始化,则自动赋以“”(整型和实型)或,0,(字符型);且每次调用它们所在的函数时,不再重新赋初值,只是保留上次调用结束时的值!,(,3,)何时使用静态内部变量,需要保留函数上一次调用结束时的值。,变量只被引用而不改变其值。,例如,:,f(,int,a),auto,int,b=0;static,int,c=3;,b+=1;c+=1;,return(a+b+c);,main(),int,a=2,,,i;,for(i=0;i3;i+),printf,(“%3d”,,,f(a);,789,举例,5,:自动变量与静态局部变量的存储特性。,void auto_static(void),int var,_auto=0;/*,自动变量:每次调用都重新初始化*,/,static,int var,_static=0;/*,静态局部变量:只初始化,1,次*,/,printf,(“,var,_auto=%d,var,_static=%dn”,var,_auto,var,_static);,+,var,_auto;,+,var,_static;,main(),int,i;,for(i=0;i5;i+)auto_static();,说明,:,1,、局部静态变量存储在静态存储区,在程序的整个运行期间都不释放,;,2,、局部静态变量是在,编译时,赋初值的,即只赋值一次,在程序的运行期间,每次调用函数时不再重新赋初值,但函数被多次调用时,本次静态变量的值继承上次函数被调用时对静态变量的改变,;,3,、局部静态变量在定义时不赋初值,编译时系统自动赋初值,0;,而对于自动变量,如果不赋初值则它的值是一个不确定的值。,4,、,C,语言规定只有全局变量、数组和局部静态变量、数组才能进行初始化,原因在于,静态存储区的数组是在编译时进行初始化的,只初始化一次,而动态存储区的数组在每次函数被调用时都进行初始化,如果数组比较大将直接影响程序的运行效率和占用的内存空间。,5,、局部静态变量在函数调用结束后仍然存在,但只能被这个函数再次调用,不能被其他函数调用。,三、寄存器变量,(,register),寄存器是计算机,cpu,的重要组成部分,在一个程序中对于频繁使用的变量从内存取数送到运算器中运算,再把运算的结果送回到内存中要花费很多的时间。在,C,语言中允许将一些频繁使用的变量存放在计算机的寄存器中,以节省运算时间,提高效率,这种变量就称为寄存器变量。,定义格式如下:,register,数据类型 变量表;,int fac,(,int,n),register,int,i,,,f=1;,for(i=1;i=n;i+)f=f*i;,return f;,main(),int,i;for(i=1;i=5;i+),printf,(“%d!=%dn”,,,i,,,fac,(i);,(,1,)只有局部变量才能定义成寄存器变量,即全局变量不行。,(,2,)对寄存器变量的实际处理,随系统而异。例如,微机上的,MSC,和,TC,将寄存器变量实际当作自动变量处理。,(,3,)允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量。,全局变量的存储方式,全局变量是在函数的外部定义的,存放在内存的静态存储区中,它可以被程序中的所有函数所引用。,全局变量可以被它所在的源程序中的所有函数引用,这一点我们在前面已经讲过了。一个,c,语言程序可以有一个或多个源程序组成,一个源文件中的函数能否引用其他源文件中的全局变量呢,?,分为,两种,情况,:,1,、当在程序中希望全局变量只限于在本源文件使用,不能被其他的文件中的函数引用,可以在定义这个全局变量时用,static,进行说明,这时的,static,不代表静态的含义。,静态外部变量只允许被本源文件中的函数引用,其定义格式为:,static,数据类型 外部变量表,2,、允许其他文件中的函数引用。如果在一个文件中引用另一个文件中定义的全局变量,应当在需要引用的地方,使用,extern,进行说明。,非静态外部变量允许被其它源文件中的函数引用,定义时缺省,static,关键字的外部变量,即为非静态外部变量。其它源文件中的函数,引用非静态外部变量时,需要在引用函数所在的源文件中进行说明:,extern,数据类型 外部变量表;,注意,:在函数内的,extern,变量说明,表示引用本源文件中的外部变量!而函数外(通常在文件开头)的,extern,变量说明,表示引用其它文件中的外部变量。,静态局部变量和静态外部变量同属静态存储方式,但两者区别较大:,(,1,)定义的位置不同。静态局部变量在函数内定义,静态外部变量在函数外定义。,(,2,)作用域不同。静态局部变量属于内部变量,其作用域仅限于定义它的函数内;虽然生存期为整个源程序,但其它函数是不能使用它的。,静态外部变量在函数外定义,其作用域为定义它的源文件内;生存期为整个源程序,但其它源文件中的函数也是不能使用它的。,(,3,)初始化处理不同。静态局部变量,仅在第,1,次调用它所在的函数时被初始化,当再次调用定义它的函数时,不再初始化,而是保留上,1,次调用结束时的值。而静态外部变量是在函数外定义的,不存在静态内部变量的“重复”初始化问题,其当前值由最近,1,次给它赋值的操作决定。,务必牢记,:把局部变量改变为静态内部变量后,改变了它的存储方式,即改变了它的生存期。把外部变量改变为静态外部变量后,改变了它的作用域,限制了它的使用范围。因此,关键字“,static”,在不同的地方所起的作用是不同的。,变量生存时间,变量属性,静态存储,动态存储,全局变量,数据类型,存储类别,局部变量,变量作用域,动态存储,寄存器变量,自动变量,形参,静态存储,外部变量,静态局部变量,静态外部变量,当一个源程序由多个源文件组成时,语言根据函数能否被其它源文件中的函数调用,将函数分为,内部函数,和,外部函数,。,内部函数和外部函数,内部函数(又称静态函数),外部函数,多个源程序文件的编译和连接,如果在一个源文件中定义的函数,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用,
展开阅读全文

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


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

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

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

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

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

gongan.png浙公网安备33021202000488号   

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

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

客服