各种变量的作用域不同,就其本质来说是因变量的存储类型不同。所谓存储类型是指变量占用内存空间的方式,也称为存储方式。
变量的存储方式可分为静态存储和动态存储两种。
静态存储变量通常是在变量定义时就划分存储单元并一直保持不变,直至整个程序结束。全局变量即属于此类存储方式。动态存储变量是在程序执行过程中,使用它时才分配存储单元,使用完毕立即释放。典型的例子是函数的形式参数,在函数定义时并不给形参分配存储单元,只是在函数被调用时,才予以分配,调用函数完毕立即释放。如果一个函数被多次调用,则反复地分配、释放形参变量的存储单元。从以上分析可知,静态存储变量是一直存在的,而动态存储变量则时而存在时而消失。把这种由于变量存储方式不同而产生的特性称为变量的生存期,生存期表示了变量存在的时间。生存期和作用域是从时间和空间这两个不同的角度来描述变量的特性,这两者既有联系又有区别。一个变量究竟属于哪一种存储方式,并不能仅从其作用域来判断,还应有明确的存储类型说明。
在C语言中,变量的存储类型有四种:自动变量(auto)、寄存器变量(register)、外部变量(extern)、静态变量(static)。
自动变量和寄存器变量属于动态存储方式,外部变量和静态变量属于静态存储方式。在介绍了变量的存储类型之后,可以知道对一个变量的说明不仅应说明其数据类型,还应说明其存储类型。因此,变量说明的完整形式应为:
<存储类型说明符><数据类型说明符><变量名1,变量名2,…;>
例如:
static int a,b; 说明a,b为静态类型变量
auto char c1,c2; 说明c1,c2为自动字符变量
static int a[5]={1,2,3,4,5}; 说明a为静态整型数组
extern int x,y; 说明x,y为外部整型变量
下面分别介绍以上四种存储类型。
1.自动变量
自动变量的类型说明符为auto。这种存储类型是C语言程序中使用最广泛的一种类型。C语言规定,函数内凡未加存储类型说明的变量均视为自动变量,也就是说自动变量可省去说明符auto。在前面各章的程序中所定义的变量凡未加存储类型说明符的都是自动变量。
例如:
int main()
{
int i,j,k;
char c;
·
·
·
}
等价于:
int main()
{
auto int i,j,k;
auto char c;
·
·
·
}
自动变量具有以下特点:
(1)自动变量的作用域仅限于定义该变量的个体内。在函数中定义的自动变量,只在该函数内有效。在复合语句中定义的自动变量只在该复合语句中有效。
例如:
(2)自动变量属于动态存储方式,只有在使用它,即定义该变量的函数被调用时才给它分配存储单元,开始它的生存期。函数调用结束,释放存储单元,结束生存期。因此函数调用结束之后,自动变量的值不能保留。在复合语句中定义的自动变量在退出复合语句后也不能再使用,否则将引起错误。
例如,以下程序段:
auto int a;
printf("\n input a number:\n");
scanf("%d",&a);
if(a>0)
{
auto int s,p;
s=a+a;
p=a*a;
}
printf("s=%dp=%d\n",s,p);
s、p是在复合语句内定义的自动变量,只能在该复合语句内有效。但程序中却试图在退出复合语句之后用printf语句输出s和p的值,这显然会引起错误。
(3)由于自动变量的作用域和生存期都局限于定义它的个体内(函数或复合语句内),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量也可与该函数内部的复合语句中定义的自动变量同名。
例如,下列程序:
int main()
{
auto int a,s=100,p=100;
printf("\n input a number:\n");
scanf("%d",&a);
if(a>0)
{
auto int s,p;
s=a+a;
p=a*a;
printf("s=%d,p=%d\n",s,p);
}
printf("s=%d,p=%d\n",s,p);
return 0;
}
本程序在main()函数中和复合语句内两次定义了变量s、p为自动变量。按照C语言的规定,在复合语句内,应由复合语句中定义的s、p起作用,故s的值应为a+a,p的值为a*a。退出复合语句后的s、p应为main()函数所定义的s、p,其值在初始化时给定,均为100。从输出结果可以分析出两个s和两个p虽变量名相同,但却是两个不同的变量。
2.外部变量
外部变量的类型说明符为extern。在前面介绍全局变量时已介绍过外部变量,这里再补充说明外部变量的几个特点:
(1)外部变量和全局变量是对同一类变量的两种不同提法。全局变量是从它的作用域角度提出的,外部变量则是从其存储方式角度提出的,表示了它的生存期。
(2)当一个源程序由若干个源文件组成时,在一个源文件中定义的外部变量在其他的源文件中也有效。
例如,下面的源程序由源文件F1.C和F2.C组成。
源文件F1.C:
int a,b; //外部变量定义
char c; //外部变量定义
int main()
{
·
·
·
}
源文件F2.C:
extern int a,b; //外部变量说明
extern char c; //外部变量说明
fun c(int x,y)
{
·
·(www.xing528.com)
·
}
在F1.C和F2.C两个文件中都要使用a、b、c三个变量。在F1.C文件中把a、b、c都定义为外部变量。在F2.C文件中用extern把三个变量说明为外部变量,表示这些变量已在其他文件中定义,并把这些变量的类型和变量名告诉编译系统,编译系统不再为它们分配内存空间。
3.静态变量
静态变量的类型说明符为static。静态变量属于静态存储方式,但是属于静态存储方式的变量不一定就是静态变量,例如外部变量虽属于静态存储方式,但不一定是静态变量,必须由static加以定义后才能成为静态外部变量,或称静态全局变量。对于自动变量,前面已经介绍它属于动态存储方式,但是也可以用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储方式。
(1)静态局部变量
在局部变量的说明前再加上static说明符就构成静态局部变量。
例如:
static int a,b;
static float array[5]={1,2,3,4,5};
静态局部变量属于静态存储方式,它具有以下特点:
①静态局部变量在函数内定义,但不像自动变量那样,当调用时就存在,退出函数时就消失。静态局部变量始终存在着,也就是说它的生存期为整个源程序。
②静态局部变量的生存期虽然为整个源程序,但其作用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后,尽管该变量还继续存在,但不能使用它。
③允许对构造的静态局部变量赋初值。在数组一章中,介绍数组初始化时已做过说明。若未赋予初值,则由系统自动赋以0值。
④对基本类型的静态局部变量,若在说明时未赋予初值,则系统自动赋以0值。而对自动变量不赋初值,则其值是不定的。根据静态局部变量的特点,可以看出它是一种生存期为整个源程序的变量。虽然离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用,而且保存了前次被调用后留下的值。因此,当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,因此仍以采用静态局部变量为宜。
【例6.15】静态局部变量的应用。
程序内容如下:
1 #include<stdio.h>
2 int main()
3 {
4 int i;
5 void f(); //函数声明
6 for(i=1;i<=5;i++)
7 f(); //函数调用
8 return 0;
9 }
10 void f() //函数定义
11 {
12 auto int j=0;
13 ++j;
14 printf("%d\n",j);
15 return;
16 }
程序结果如图6.12所示:
图6.12 例6.15程序结果图
程序中定义了函数f(),其中的变量j说明为自动变量并被赋予初始值0。当main()中多次调用f时,j均赋初值为0,故每次输出值均为1。现在把j改为静态局部变量。
程序如下:
1 #include<stdio.h>
2 int main()
3 {
4 int i;
5 void f();
6 for(i=1;i<=5;i++)
7 f();
8 return 0;
9 }
10 void f()
11 {
12 static int j;
12 ++j;
13 printf("%d\n",j);
14 return;
15 }
运行结果如下:
1
2
3
4
5
由于j为静态局部变量,没初始化,系统自动初始化为0。j能在每次调用后保留其值并在下一次调用时继续使用,所以输出值成为累加的结果。
(2)静态全局变量
全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。两者的区别在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的;而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其他源文件中不能使用。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其他源文件中引起错误。
从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式,即改变了它的生存期;而把全局变量改变为静态变量后则是改变了它的作用域,限制了它的使用范围。因此,static这个说明符在不同的地方所起的作用是不同的,使用时应注意。
4.寄存器变量
上述各类变量都存放在存储器内,因此当对一个变量频繁读写时,必须要反复访问内存储器,从而花费大量的存取时间。为此,C语言提供了另一种变量,即寄存器变量。这种变量存放在CPU的寄存器中,使用时,不需要访问内存,直接从寄存器中读写,这样可提高存取效率。寄存器变量的说明符是register。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量。
【例6.16】求1+2+3+…+200的值。
程序内容如下:
1 #include<stdio.h>
2 int main()
3 {
4 register int i,s=0;
5 for(i=1;i<=200;i++)
6 s=s+i;
7 printf("s=%d\n",s);
8 return 0;
9 }
程序结果如图6.13所示:
图6.13 例6.16程序结果图
本程序循环200次,i和s都将频繁使用,因此可定义为寄存器变量。
对寄存器变量还需要说明以下几点:
(1)只有局部自动变量和形式参数才可以定义为寄存器变量,因为寄存器变量属于动态存储方式。凡需要采用静态存储方式的变量均不能定义为寄存器变量。
(2)在Turbo C、MSC等微机上使用的C语言中,实际上是把寄存器变量当成自动变量处理的,因此速度并未提高。而在程序中允许使用寄存器变量只是为了与标准C保持一致。
(3)即使能真正使用寄存器变量的机器,由于CPU中寄存器的个数是有限的,因此使用寄存器变量的个数也是有限的。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。