变量的作用域和生存期:变量是对程序中数据存储的抽象,它具有以下属性:(1)变量的数据类型。C语言程序中的变量都是有类型的。数据类型是变量的运算属性的抽象,它决定了该变量的取值范围和可以施加的运算种类。(2)变量的作用域。变量的作用域是指一个变量在程序中的使用范围。(3)变量的生存期。变量的生存期是指变量生成以及被撤销的时间。(4)变量的存储区。变量的存储区是指存储变量的存储器类型以及存储机制。变量的作用域、生存期、存储区就是这里要讨论的问题。1.局部变量和全局变量变量的作用域是从空间的角度来看变量,这个变量在程序中的哪个域内是可以识别的,也称为可见(或可用)的。大体上可以分成两种:全局可用(全局变量)与局部可用(局部变量)局部变量是定义在一个程序块内的变量。程序块可能是一个函数体(主函数),也可能是一个循环体或是选择结构中的一个分支语句块,也可以是任何一个用花括号括起来的语句块(复合语句)全局变量定义在函数之外,不属于任何语句块一般来说,定义在什么范围的变量,其作用域就在那个范围,并且在定义语句开始到这个域结束的范围(域)内被使用,这个域之外是不可见的。在C语言中,凡是声明函数内部的变量都是局部变量(包含参数的形参)。【例4-8】演示局部变量的作用域•Floatf1(inta)•{•intb,c;•…….•}•Charf2(intx,inty)•{•inti,j;•…….•}•Intmain(void)•{•Intm,n;•…….•}•说明:主函数中定义的变量m,n只在主函数中有效,主函数也不能使用其它函数中定义的变量;不同函数中可以使用相同名称的变量,他们表达不同的对象,互不干扰。例如,上面在f1函数中定义了变量b和c,倘若在f2函数中也定义变量b和c,它们在内存中占不同的单位,互不混淆,但在同一作用域内不可定义同名的变量。【例4-9】演示全局变量的作用域•Intp=1,q=5;•Floatf1(inta)•{•intb,c;•…….•}•Charc1,c2;•Charf2(intx,inty)•{•inti,j;•…….•}•Intmain(void)•{•Intm,n;•…….•}读程序,分析执行结果:inti=10;main(){intj=1;j=fun();printf(“%d,”,j);j=fun();printf(“%d”,j);}fun(){intk=0;k=k+i;i=i+10;return(k);}2.动态变量与静态变量从变量值存在的时间(即生存期)角度来分,变量可以分为静态变量和动态变址。任何一个在内存中运行的程序,内存区都被分成代码区和数据区两大部分,而数据区又被分为静态存储区和动态存储区两部分。动态存储区中的变量在程序进入所在的程序块时被创建(分配存储空间),结束时被撤销(释放存储空间),当所在的块结束后,各变量的值不再保留。这种分配和释放是动态的。如在一个程序中两次调用同一个函数,分配给此函数中局部变量的存储空间地址可能是不同的。这些变量必须由程序员显式地进行初始化,否则它们的初始值是不确定的。静态存储区是在程序编译时分配的存储区,分配在静态存储区的变量在程序开始执行时被创建并自动初始化(数值变量被初始化为0),当程序结束时才被撤销,所以常称静态变量。生存期是从程序开始运行到程序结束。全局变量就是被分配在静态存储区的。4.5.2C语言中变量的存储类型根据变童的作用域将变量分为全局变量和局部变量,根据变量的生存期将变量分为动态变量和静态变量。因此,C语言根据作用域和生存期将变量整合成四种存储类型。(1)局部自动类型。在函数内部用标识符auto或register声明。(2)静态局部类型。在函数内部,使用Static声明。(3)静态全局类型。在函数外部,使用Static。声明,也称为静态外部变量。(4)全局类型。不需要标识符声明。在函数外部直接声明即可,通常称为外部变量。1.AUTO存储类型和REGISTER存储类型auto声明符的作用就是告诉编译器将变量分配在动态存储区。也就是说,使用auto声明的变量是局部变量。其格式为:[auto]数据类型变量名[=初值表达式],……;其中,方括号表示可省略,auto是自动变量的存储类别标识符。如果省略auto,系统默认为此变量为auto。函数的参数也是一种自动变量。register的作用是用来声明寄存器(寄存器就是CPU自己的“小内存”,它的特点是容量小、速度快)存储自动变量。这类变量具有局部变量的所有特点。当把一个变量指定为寄存器存储类别时,系统就将它存放在CPU的一个寄存器中。通常把使用频率较高的变量(如循环次数较多的循环变量)定义为register类别。函数的形参也可以使用寄存器变量。一个计算机系统中的寄存器数量是有限的,因此不能定义任意多个寄存器变量,而且对于不同的系统来说,所允许使用的最大寄存器数量也是不同的。在程序中如果遇到指定为register类型的变量,系统会尽可能地去实现它。但因为条件所限(如寄存器数量有限),系统会自动将它们(即未能实现的部分)处理成自动类型(auto)变量。2.静态局部类型定义局部变量时,使用Static修饰,可以在不改变局部变量的可见域的前提下,使变量成为静态的,即当函数撤销后,变量的值还保留。或者说,这些变量的生存期是永久的,只是在变量的作用域外是不可见的。这样,避免了全局变量的值可以被多处修改将引起的副作用,又可以使函数基于前一次调用的值的基础上工作。【例4-12】静态局部变量。在该程序中,每次调用fac(i),打印出一个i!,同时保留这个i!的值以便下次再乘(i+1)。若源程序是由多个文件组成的,用Static声明外部变量,其作用域仅限于所在的文件,而不用static声明的外部变量的作用域为整个程序(组成源程序的多个文件)。这种外部变量(全局变量)称为静态全局(外部)变量,在程序设计中,常由若干人分别完成各个模块,各人可以独立地在其设计的文件中使用相同的外部变量名而互不相干,只需在每个文件中的外部变量前加上Static即可。这就为程序的模块化、通用性提供了方便。需要指出的是,对外部变量加上Static声明,并不是说此时变量放在静态存储区,而不加Static的外部变量放在动态存储区。这两种形式的外部变量都是静态存储方式,只是作用范围不同而已,都是在编译时分配内存的。3.静态全局类型•利用全局变量实现函数之间传递数据:全局变量从定义点开始对所有的函数有效,因此可以利用它来实现函数间数据传递。intsum;main(){inti,j;printf(“请输入i,j:”);scanf(“%d%d”,&i,&j);plus(i,j);printf(“\ni+j=%d”,sum);}plus(x,y)intx,y;{sum=x+y;}main(){intk=4,m=1,p;p=func(k,m);printf(“%d,”,p);p=func(k,m);printf(“%d\n”,p);}func(a,b)inta,b;{staticintm=0,i=2;i+=m+1;m=i+a+b;return(m);}main(){inta=2,i;for(i=0;i3;i++)printf(“%d”,func(a));}func(inta){intb=0;staticc=3;b++;c++;return(a+b+c);}main(){inta=3,b=2,c=1;c-=++b;b*=a+c;{intb=5,c=12;c/=b*2;a-=c;printf(“%d,%d,%d,”,a,b,c)a+=--c;}printf(“%d,%d,%d\n”,a,b,c)}main(){intswap();externinta,b;a=3;b=10;swap();printf(“a=%d”,b=%d\n”,a,b);}inta,b;swap(){inttemp;temp=a;a=b;b=temp;}main(){ints,i,sum();for(i=1;i11;i++)s=sum(i);printf(“s=%d\n”,s);}sum(intz){intx=0;return(x+=z);}将上题函数sum中x变量的存储类型定义为static型,即staticintx=0;程序的执行结果是:intx=3;main(){func(x);printf(“x=%d\n”,x);}func(x)intx;{x=8;}main(){intx=20;func(x);printf(“x=%d\n”,x);}func(intx){x=30;}staticintx=5;main(){autointx=3;printf(“1.x=%d\n”,x);f1();f2();printf(“4.x=%d\n”,x);}f1(){x+=1;printf(“2.x=%d\n”,x);}f2(){intx=1;printf(“3.x=%d\n”,x);}以下程序输出的是:intd=1;voidfun(intp){intd=5;d+=p++;printf(“%d”,d);}main(){inta=3;fun(a);d+=a++;printf(“%d”,d);}