第04章 变量的存储类型.docx
- 文档编号:23454972
- 上传时间:2023-05-17
- 格式:DOCX
- 页数:23
- 大小:46.29KB
第04章 变量的存储类型.docx
《第04章 变量的存储类型.docx》由会员分享,可在线阅读,更多相关《第04章 变量的存储类型.docx(23页珍藏版)》请在冰豆网上搜索。
第04章变量的存储类型
第4章变量的存储类型
4.1概述
C语言中的变量具有两种属性:
根据变量所持有数据的性质不同而分为各种数据类型;根据变量的存储方式不同而分为各种存储类型.变量的数据类型决定了该变量所占内存单元的大小及形式;变量的存储类型规定了该变量所在的存储区域,因而规定了该变量作用时间的长短,即寿命的长短,这种性质又称为"存在性".变量在程序中说明的位置决定了该变量的作用域,即在什么范围内可以引用该变量,"可引用"又称为"可见",所以这种性质又称为"可见性".
计算机的内存和CPU中的寄存器都可以存放数据,变量究竟存放在何处则由存储类来决定.存储类型用来说明变量的作用域,生存期,可见性和存储方式.下面解释几个概念:
1作用域:
是该变量在其上有定义的程序部分,通俗的说,即该变量起作用的某个程序区域。
2变量的生存期:
是指它从产生到消亡的存在时间,即变量从定义开始到它所占有的存储空间被系统收回为止的这段时间。
3变量的可见性的含义:
在某个程序区域,可以对变量进行访问(或称存取)操作,我们则称该变量在该区域为可见的,否则为不可见的。
再引入几个概念:
4全局变量和局部变量
在一个函数内部或复合语句内部定义的变量叫内部变量,又称为"局部变量"。
在函数外定义的变量称为外部变量,又称为"全局变量"。
如:
intx;
voidmain()
{
inta,b;
floatc;
……..
}
x定义在函数外,是全局int型变量
a,b定义在main()函数内是局部int型变量
c定义在main()函数内是局部float型变量
6动态存储变量和静态存储变量。
在程序运行期间,所有的变量均需占有内存,有的是临时占用内存,有的是整个程序运行过程中从头到尾占用内存。
对于在程序运行期间根据需要进行临时性动态分配存储空间的变量称为"动态存储变量",对于在程序运行期间永久性占用内存的变量称为"静态存储变量".
一个正在运行的程序可将其使用内存的情况分为如下三类(如下图):
程序代码区:
程序的指令代码存放在程序代码区。
静态存储区:
静态存储变量存放区,包括全局变量。
动态存储区:
存放局部自动变量,函数的形参以及函数调用时的现场保护和返回地址等。
图4-1内存分配情况
变量定义的一般形式为:
<存储类型>数据类型变量名表;
存储类型包括:
auto自动型
register寄存器型
extern外部参照型
static静态型
4.2自动型变量[auto]
自动变量用关键字auto作存储类型声明
如
voidmain
{
autointx,y;
autofloatz;
……..
}
在主函数内定义了自动型int变量x,y和自动型float变量z,在函数内或复合语句中定义自动型变量时auto可缺省,所以上例可以简写为:
voidmain
{
intx,y;
floatz;
……..
}
前面章节所定义的变量用的就是这种简化形式,所以前面章节所用变量都是auto型变量,一般情况下auto都缺省。
下面再看一个例子
if(x!
=y)
{
inti;
for(i=0;i<10;i++)
{
intj;
……
}
}
在条件判断后的那个复合语句中定义了一个自动型int变量i,在for循环后的那个复合语句中定义了一个自动型int变量j,虽然我们不提倡这种说明变量的方式,但C++可以这样定义.
2.作用域及寿命:
由于自动型变量只能作内部变量,所以自动变量只在定义它的函数或复合语句内有效,即"局部可见"。
.变量的作用域是指该程序中可以使用该变量名字的范围。
对于在函数开头声明的自动变量来说,其作用域是声明该变量的函数。
不同函数中声明的具有相同名字的各个局部变量之间没有任何关系。
函数的参数也是这样的,实际上可以将它看作是局部变量。
例4.1
#include
voidmain()
{
intx=5;//auto缺省……….
(1)
printf("x=%d\t",x);
if(x>0)
{
intx=10;//………………
(2)
printf("x=%d\t",x);
}
printf("x=%d\n",x+2);
}
运行结果:
x=5x=10x=7
第一个printf()语句中的x的是
(1)处说明的,所以x=5;第二个printf()语句中的x的是
(2)处说明的,虽然if语句后的一对大括号,是包含在外层的大括号内,即前面一个x变量的内存还没释放,但C++规定当出现类似的情况时,以内层说明优先,即相当于内层说明的变量x是另外一个变量x’,在其所在的大括号内如果不包括更深层次的同名变量说明,则其中所引用的x就是x’;所以x=10;
第三个printf()语句中的x的是
(1)处说明的,因为这时
(2)处说明的变量x已释放;故结果为x=7.
例4.2下面的例子说明了自动变量的特性。
#include
voidfunc();
voidfunc()
{
autointa=0;
printf("aoffunc()=%d\n",++a);
}
voidmain()
{
inta=10;
func();//调用func()函数
printf("aofmain()=%d\n",++a);
func();//调用func()函数
func();//调用func()函数
}
该程序的输出结果为:
aoffunc()=1
aofmain()=11
aoffunc()=1
aoffunc()=1
当第一次调用func()函数时,系统首先在动态存储区为func()函数的自动变量a分配内存空间,并将初值0存放在这一空间内,接着用printf()把自动变量a自增1后再输出显示值1,随后遇到右大括号就离开它的作用域,这时func()函数内的自动变量的内存将释放,该变量将不存在(即寿命到),然后返回到主函数的下一条语句。
它又是一条printf()调用语句,把主函数内的同名自动变量a自增1后再输出显示,其值为11,接着,第2次调用func()函数,系统再次为func()函数内的自动变量a分配内存空间,并初始化为0重复执行上述过程。
例4.3下面的程序说明自动变量的初始化和作用域
程序如下:
#include
intn;
voidshow();
voidshow()
{
autointi=3;
n++;
i++;
printf("inputthevalue:
n=%di=%d\n",n,i);
{
autointi=10;
i++;
printf("nowthevaluei=%d\n",i);
}
printf("thenthevaluei=%d\n",i);
}
voidmain()
{
autointi;
autointn=1;
printf("atfirstn=%d\n",n);
for(i=1;i<3;i++)
{
show();
}
printf("atlastn=%d",n);
}
程序运行结果:
atfirstn=1
inputthevalue:
n=1i=4
nowthevaluei=11
thenthevaluei=4
inputthevalue:
n=2i=4
nowthevaluei=11
thenthevaluei=4
atlastn=1
分析:
show函数的定义在主函数之前,所以不需要函数说明。
在函数外定义的变量n是全局变量初值为0,其寿命和作用域是全局的,在main()函数内定义的变量n是局部变量初值为1,其作用域是在其所在的大括号对内,在其范围内定义的变量n与全局变量n重名,根据标准中的就近原则规定,在main()函数中出现的n就是局部变量n。
在show()函数中的变量n是全局变量,其值被加1后存入n,故第一次调用show()时n的值为1,而第二次调用时n的值再被加1,故n的值为2;而对变量i,由于是局部auto型变量,故两次调用时i的值是一致的。
在show函数体的复合语句中,分别有一个自动变量i,它们虽然同名,但是是两个不同的变量。
外层的i初始化为3,而内层初始化为10。
内层的i只是在复合语句内有效,对外层的i值没有影响。
主函数main()在执行for循环语句时,两次调用了show()函数。
4.3寄存器型变量[register]
1.定义
在函数内或复合语句内定义,例如:
voidmain()
{
registerinti;
for(i=0;i=<100;i++)
{
}
}
寄存器型变量存储在CPU的通用寄存器中,因为数据在寄存器中操作比在内存中快得多,因此通常把程序中使用频率最高的少数几个变量定义为register型,目的是提高运行速度,从而节省了大量的时间。
大大加快了程序的运行速度。
但并不是用户定义的寄存器型变量都被放入CPU寄存器中,能否真正把它们放入CPU寄存器中是由编译系统根据具体情况做具体处理的。
2.分配寄存器的条件是:
①有空闲的寄存器;
②变量所表示的数据的长度不超过寄存器的位长;
3.作用域和寿命同auto类型,也是在定义它的函数或复合语句内有效,即"局部可见"。
例4.4用寄存器变量提高程序执行速度。
#include
//函数的形参也可以指定为寄存器变量,一个函数一般以拥有2个寄存器变量为宜//
#definet10000
voiddelay1();
voiddelay2();
voiddelay1()
{
registerunsignedi=0;
for(;i { } } voiddelay2() { unsignedi; for(i=1;i { } } voidmain() { unsignedinti; printf("\a调用delay1()第一次延时! \n"); for(i=0;i<60000;i++) { delay1(); } printf("\a第1次延时结束! \n调用delay2()第2次延时! \n"); for(i=0;i<60000;i++) { delay2(); } printf("\a第2次延时结束! \n"); } 该程序运行结果为; 调用delay1()第一次延时! 第1次延时结束! 调用delay2()第2次延时! 第2次延时结束! 由于delay1()函数使用了寄存器,它的执行速度比不使用寄存器变量的delay2()函数要快。 尽管使用寄存器变量可以提高程序运行的速度,但计算机的寄存器是有限的,为确保寄存器用于最需要的地方,应将使用最频繁的变量说明为寄存器存储类型。 4.4外部参照型变量[extern] 1.定义 extern型变量一般用于在程序的多个编译单位之间传送数据,在这种情况下指定为extern型的变量是在其它编译单位的源程序中定义的,它的存储空间在静态数据区,在程序执行过程中长期占用空间。 要访问另一个文件中定义的跨文件作用域的全局变量,必须进行extern说明。 例如: /*file1.c*//*file2.c*//*file3.c*/ eternintx;externintx;intx=0; voidmain()voidfun1()voidfun2() {{{ x++;x+=3;printf("%d",x); }}} file1.c和file2.c中的externintx;告诉编译程序X是外部参照变量,应在本文件之外去寻找它的定义。 所以上面的x虽在两个源文件中,但它们是同一个变量。 在文件之外的file3.c中,定义了intx=0,即为它们调用的变量。 如果外部变量不在文件的开头部分定义,其有效的作用范围只限于从定义处到文件结束。 如果定义点之前的函数想引用外部变量,则应该在引用前用关键字extern,从而对该变量作外部声明,有了此声明,就可以从声明处起,合法的使用该外部变量。 作用域及寿命: 全局存在,全局可见; 例4.5下例说明了外部变量的特性。 #include intn=100; voidhanshu(); voidhanshu(void) { n-=20; } intmain(void) { printf("n=%d\n",n); for(;n>=60;) { hanshu(); printf("n=%d\n",n); } return0; } 执行结果: n=100; n=80; n=60; n=40; n是int型外部变量,定义时被显示初始化为100。 进入for语句时,n值开始为100,每次调用hanshu()后值减少20,直到n值小于60为止。 for循环体三次调用函数hanshu(),第二,第三次调用执行函数体中的赋值语句"n-=20;"时n的值就是上次调用后的值。 可见外部变量值的连续性。 我们把上面的程序改一下。 如果外部变量n的定义性说明在hanshu之后,系统在该处给变量分配存储并执行初始化,由于hanshu中的n值是在n定义之前引用的,因此必须要用extern对n做引用说明(如下面程序),外部变量引用说明时不分配存储,也不初始化,但在实际编程中我们不提倡这种用法。 #include externintn; voidhanshu(); voidhanshu(void) { n-=20; } intn=100; intmain(void) { printf("n=%d\n",n); for(;n>=60;) { hanshu(); printf("n=%d\n",n); } return0; } 执行结果: n=100; n=80; n=60; n=40; 使用这样的全局变量应十分慎重,因为在执行一个文件中的函数时,可能会改变了该全局变量的值,它会影响到另一文件中的函数执行结果。 例4.6用extern声明外部变量: 本程序的作用是给定b的值,输入a和m,求a*b,和a 的值。 文件file1.c中的内容为: #include inta; intm; intpower(); voidmain() { intb=3,c,d; printf("inputthenumberaanditspowerm: \n"); scanf("%d,%d",&a,&m); c=a*b; printf("%d*%d=%d\n",a,b,c); d=power(); printf("%d**%d=%d",a,m,d); } 文件file2.c中的内容为: externinta; externintm; intpower(); { inti,y=1; for(i=1;i<=m;i++) { y*=a; } return(y); } 该程序的运行结果为: inputthenumberaanditspowerm: 5,4//输入 5*3=15//输出 5**4=625 从上面可以知道,file2.c文件中的开头有两个extern声明,它们声明在本文件中出现的变量a和m是已经在其它文件定义过的外部变量,本文件不必再次为它分配内存。 也就是说,本来外部变量a和m是定义在file1.c中的,但用extern扩展到file2.c上了,这样即使程序有N个源文件,在一个文件中定义了外部整型变量a,其它N-1个文件都可以引用。 4.5静态型变量[static] 1.定义 静态型变量既可以在函数或复合语句内进行,也可以在所有函数之外进行。 在函数或复合语句内部定义的静态变量称为局部静态变量,在函数外定义的静态变量称为全局静态变量。 有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释放,在下次该函数调用时,该变量已有值,其值就是上一次函数调用结束时的值。 这时就应该指定该局部变量为"静态局部变量",用关键字static进行声明。 例如: staticfloatx;/*定义全局静态变量*/ voidmain() { staticinty;/*定义y局部静态变量*/ …… } 局部静态变量和自动变量一样只有定义性说明,没有引用性说明,因此必须先定义后引用。 外部静态变量的初始化同外部变量。 局部静态变量在第一次进入该块时执行一次且仅执行一次初始化;在有显式初始化的情况下,初值由说明符中的初值说明来确定;在无显式初始化情况下,初值与外部变量无显式初始化时的初值相同。 2.作用域和寿命 static类型变量都是全局寿命。 全局static变量全局可见。 局部static变量局部可见。 例4.7考察静态变量的值。 #include inta=2; intf(); intf() { autointb=0; staticintc=3; b++; c++; return(a+b+c); } voidmain() { inti; for(i=0;i<3;i++) { printf("%d\t",f()); } } 运行结果为: 789 在第一次调用f()函数时,b的初值为0,第一次调用结束时,b=1,c=4,a+b+c=7,由于c是静态局部变量,在函数调用后,它并不释放,仍保留c=4。 在第2次调用f()函数时,b的初值为0,而c的初值为4(上次调用结束时的值)。 注意事项: (1).对静态局部变量属于静态存储类别,在静态存储区内分配存储单元。 在程序整个运行期间都不释放。 而自动变量(动态局部变量)属于动态存储类别,占动态存储空间而不占静态存储空间,函数调用结束后即释放。 (2).对静态局部变量只赋初值一次,以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。 而对自动变量赋初值,每次用一次函数重新给一次初值,相当于执行一次赋值语句。 (3).如在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋值初值0(对数值型变量)或空字符(对字符变量)。 而对自动变量来说,如果不赋初值则它的值是一个不确定的值。 这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另配置存储单元,而所分配的单元中的值是不确定的。 (4).有时在程序设计中希望某些外部变量只限于被本文件引用,而不能被其它文件引用。 这时可以在定义外部变量时加一个static声明。 例如: 在上文关于extern讲解中的实例,作如下改动 /*file1.c*//*file2.c*//*file3.c*/ eternintx;externintx;staticintx=0; voidmain()voidfun1()voidfun2() {{{ x++;x+=3;printf("%d",x); }}} file3.c中定义了全局变量x,但是用了static声明,因此只能用于本文件,虽然在file1.c和file2.c中用了"externintx;",但都无法使用file3.c中的全局变量x.这为程序的模式化,通用性提供了方便。 例4.8下面的程序说明外部静态变量和外部变量的区别 文件file1.c如下: #include staticfloatx; floaty; floatf2(); floatf1(); floatf1() { return(x*x); } voidmain() { x=500; y=100; printf("f1=%f,f2=%f\n",f1(),f2()); } 文件file2.c如下: externfloaty; floatf2() { return(y*y); } 输出: fl=250000.000000,f2=10000.000000 该程序包含两个文件三个函数,函数main和f1在文件file1.c中,函数f2在文件file2.c中,变量x是float型外部静态变量。 它只能在file1.c和main函数中使用。 变量y是在文件file1.c中定义的外部变量,他可以在file1.c和主函数中直接使用,也可以在file2.c中参照说明。 例4.9局部静态变量与自动变量的区别。 #include voidvalue(); voidvalue() { intau=0; staticintst=0; printf("au_variable=%d,st_variable=%d\n",au,st); au++; st++; } voidmain() { inti; for(i=0;i<3;i++) { value(); } } 程序运行结果: au_variable=0,st_variable=0 au_variable=0,st_variable=1 au_variable=0,st_variable=2 分析: 由于变量au是局部自动变量,st是局部静态变量,定义时二者都赋初值为0,main函数三次调用value()函数,au是局部自动变量,每次再调用时都要重新对au初始化;而st由于是静态变量,再调用时不再执行初始化,每次值增1,注意变量au在退出value函数时存储单元被系统收回,下次进入时重新分配存储空间。 4.6存储类型小结 1.关于类型说明 关键字auto,static,register用于定义变量的存储类型说明,其中auto通常缺省。 而关键字extern则不然,它不是用于定义变量而是用于说明某个变量,是已在本函数之外或其它源文件中定义过的外部变量,加extern说明有"延伸外部参照型变量作用域"的作用。 2.关于变量的作用域和寿命 3.关于变量的初始化 有关变量初始化的知识,在前面有关章节已讲述过,此处只对各种存储类型变量在初始化方面的区别加以总结。 (1)对于atuo型和register型变量: 由于这两种变量的内存
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第04章 变量的存储类型 04 变量 存储 类型