2.7.3 变量的存储类别
在 C语言中,变量是对程序中数据所占内存空间的一种抽象定义,定义变量时,用户定义变量的名、变量的类型,这些都是变量的操作属性。不仅可以通过变量名访问该变量,系统还通过该标识符确定变量在内存中的位置。在计算机中,保存变量当前值的存储单元有两类,一类是内存,另一类是CPU的寄存器。变量的存储类型关系到变量的存储位置,C语言中定义了4 种存储属性,即自动变量、外部变量、静态变量和寄存器变量,它关系到变量在内存中的存放位置,由此决定了变量的保留时间和变量的作用范围。
变量的保留时间又称为生存期,从时间的角度,可将变量分为静态存储和动态存储两种情况。静态存储是指变量存储在内存的静态存储区,在编译时就分配了存储空间,在整个程序的运行期间,该变量占有固定的存储单元,程序结束后,这部分空间才释放,变量的值在整个程序中始终存在;动态存储是指变量存储在内存的动态存储区,在程序的运行过程中,只有当变量所在的函数被调用时,编译系统才临时为该变量分配一段内存单元,函数调用结束,该变量空间释放,变量的值只在函数调用期存在。
变量的作用范围又称为作用域,从空间角度,可以将变量分为全局变量和局部变量。局部变量是在一个函数或复合语句内定义的变量,它仅在函数或复合语句内有效,编译时,编译系统不为局部变量分配内存单元,而是在程序运行过程中,当局部变量所在的函数被调用时,编译系统根据需要,临时分配内存,调用结束,空间释放;全局变量是在函数之外定义的变量,其作用范围为从定义处开始到本文件结束,编译时,编译系统为其分配固定的内存单元,在程序运行的自始至终都占用固定单元。
1. 自动变量
函数中的局部变量,如不专门声明为static 存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量)都属此类,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。这类局部变量称为自动变量。自动变量用关键字auto进行存储类别的声明,例如声明一个自动变量:
- int fun(int a)
- {
- auto int b,c=3; /*定义b,c为自动变量*/
- }
a 是函数fun()的形参,b、c是自动变量,并对c赋初值3。执行完fun()函数后,自动释放a、b、c所占的存储单元。
2. 外部变量
外部变量(即全局变量)是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件末尾。如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量进行“外部变量声明”。表示该变量是一个已经定义的外部变量。有了此声明,就可以从“声明”处起,合法地使用该外部变量,如程序2.13。
【程序 2.13】用extern声明外部变量,扩展程序文件中的作用域:test13.c。
- #include <stdio.h>
- int max(int x,int y) /*定义max 函数*/
- {
- int z;
- z=x>y x:y;
- return(z);
- }
- main( )
- {
- extern A,B; /*声明外部变量*/
- printf("%d\n",max(A,B)); /*调用max 函数*/
- }
- int A=13,B=-8; /*在文件末尾定义外部变量*/
在本程序文件的最后1行定义了外部变量A、B,但由于外部变量定义的位置在主函数main之后,因此本来在main函数中不能引用外部变量A、B。但由于在main函数中用extern对A和B进行了“外部变量声明”,就可以从“声明”处起,合法地使用该外部变量A和B了。
3. 静态变量
有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,这时就应该指定局部变量为静态局部变量,用关键字static进行声明。考察静态局部变量的值,如程序2.14。
【程序 2.14】静态局部变量的使用:test14.c。
- #include <stdio.h>
- fun(int a) /*定义函数fun*/
- {
- auto b=0; /*定义自动变量b,并初始化为0*/
- static c=3; /*定义静态变量c,并初始化为3*/
- bb=b+1;
- cc=c+1;
- return(a+b+c);
- }
- main()
- {
- int a=2,i;
- for(i=0;i<3;i++) /*重复调用函数f,比较函数返回值*/
- printf("%d ",fun(a));
- }
程序运行结果如下(□表示空格):
- 7□8□9
在上面的程序中,对于自动变量b,每次调用函数fun时,其值都被初始化为0,而静态变量c则保留上一次调用结束时的值,即逐次加1,所以程序运行的结果也是逐次增加1。
提示
局部变量与自动变量的不同:
(1)静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在整个程序运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动态存储空间,函数调用结束后即释放。
(2)静态局部变量在编译时赋初值,即只赋初值一次;而对自动变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
(3)如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值则它的值是一个不确定的值。
4. 寄存器变量
为提高效率,C语言允许将局部变量的值存放在CPU的寄存器中,这种变量叫做寄存器变量,用关键字register 声明。使用寄存器变量需要注意以下几点:
(1)只有局部自动变量和形式参数可以作为寄存器变量。
(2)一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量。
(3)不能使用取地址运算符“&”求寄存器变量的地址。
【程序 2.15】定义一个函数,实现阶乘功能,函数中使用寄存器变量:test15.c。
- #include <stdio.h>
- int fac(int n) /*定义阶乘函数*/
- {
- register int i,f=1; /*定义寄存器变量i,f*/
- for(i=1;i<=n;i++) /*用循环实现阶乘的功能*/
- ff=f*i;
- return(f); /*返回计算结果f*/
- }
- main()
- {
- int i;
- for(i=0;i<=5;i++)
- printf("%d! = %d\n",i,fac(i)); /*调用阶乘函数*/
- }
程序运行结果如下:
- 0!=1
- 1!=1
- 2!=2
- 3!=6
- 4!=24
- 5!=120
最后,表2.6对这4种变量存储类别的特性进行了总结。
表2.6 4种存储类型的特性