C语言中局部变量和全局变量等在内存中的存放位置.docx
- 文档编号:8961322
- 上传时间:2023-02-02
- 格式:DOCX
- 页数:10
- 大小:22.28KB
C语言中局部变量和全局变量等在内存中的存放位置.docx
《C语言中局部变量和全局变量等在内存中的存放位置.docx》由会员分享,可在线阅读,更多相关《C语言中局部变量和全局变量等在内存中的存放位置.docx(10页珍藏版)》请在冰豆网上搜索。
C语言中局部变量和全局变量等在内存中的存放位置
C语言中局部变量和全局变量变量的存储类别(static,extern,auto,register)
8.8 局部变量和全局变量
在讨论函数的形参变量时曾经提到,形参变量只在被调用期间才分配内存单元,调用结束立即释放。
这一点表明形参变量只有在函数内才是有效的,离开该函数就不能再使用了。
这种变量有效性的范围称变量的作用域。
不仅对于形参变量,C语言中所有的量都有自己的作用域。
变量说明的方式不同,其作用域也不同。
C语言中的变量,按作用域范围可分为两种,即局部变量和全局变量。
8.8.1局部变量
局部变量也称为内部变量。
局部变量是在函数内作定义说明的。
其作用域仅限于函数内,离开该函数后再使用这种变量是非法的。
例如:
intf1(inta) /*函数f1*/
{
intb,c;
……
}
a,b,c有效
intf2(intx) /*函数f2*/
{
inty,z;
……
}
x,y,z有效
main()
{
intm,n;
……
}
m,n有效
在函数f1内定义了三个变量,a为形参,b,c为一般变量。
在f1的范围内a,b,c有效,或者说a,b,c变量的作用域限于f1内。
同理,x,y,z的作用域限于f2内。
m,n的作用域限于main函数内。
关于局部变量的作用域还要说明以下几点:
1) 主函数中定义的变量也只能在主函数中使用,不能在其它函数中使用。
同时,主函数中也不能使用其它函数中定义的变量。
因为主函数也是一个函数,它与其它函数是平行关系。
这一点是与其它语言不同的,应予以注意。
2) 形参变量是属于被调函数的局部变量,实参变量是属于主调函数的局部变量。
3) 允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。
如在前例中,形参和实参的变量名都为n,是完全允许的。
4) 在复合语句中也可定义变量,其作用域只在复合语句范围内。
例如:
main()
{
ints,a;
……
{
intb;
s=a+b;
…… /*b作用域*/
}
…… /*s,a作用域*/
}
【例8.12】
main()
{
inti=2,j=3,k;
k=i+j;
{
intk=8;
printf("%d\n",k);
}
printf("%d\n",k);
}
本程序在main中定义了i,j,k三个变量,其中k未赋初值。
而在复合语句内又定义了一个变量k,并赋初值为8。
应该注意这两个k不是同一个变量。
在复合语句外由main定义的k起作用,而在复合语句内则由在复合语句内定义的k起作用。
因此程序第4行的k为main所定义,其值应为5。
第7行输出k值,该行在复合语句内,由复合语句内定义的k起作用,其初值为8,故输出值为8,第9行输出i,k值。
i是在整个程序中有效的,第7行对i赋值为3,故以输出也为3。
而第9行已在复合语句之外,输出的k应为main所定义的k,此k值由第4行已获得为5,故输出也为5。
8.8.2全局变量
全局变量也称为外部变量,它是在函数外部定义的变量。
它不属于哪一个函数,它属于一个源程序文件。
其作用域是整个源程序。
在函数中使用全局变量,一般应作全局变量说明。
只有在函数内经过说明的全局变量才能使用。
全局变量的说明符为extern。
但在一个函数之前定义的全局变量,在该函数内使用可不再加以说明。
例如:
inta,b; /*外部变量*/
voidf1() /*函数f1*/
{
……
}
floatx,y; /*外部变量*/
intfz() /*函数fz*/
{
……
}
main() /*主函数*/
{
……
}
从上例可以看出a、b、x、y都是在函数外部定义的外部变量,都是全局变量。
但x,y定义在函数f1之后,而在f1内又无对x,y的说明,所以它们在f1内无效。
a,b定义在源程序最前面,因此在f1,f2及main内不加说明也可使用。
【例8.13】输入正方体的长宽高l,w,h。
求体积及三个面x*y,x*z,y*z的面积。
ints1,s2,s3;
intvs(inta,intb,intc)
{
intv;
v=a*b*c;
s1=a*b;
s2=b*c;
s3=a*c;
returnv;
}
main()
{
intv,l,w,h;
printf("\ninputlength,widthandheight\n");
scanf("%d%d%d",&l,&w,&h);
v=vs(l,w,h);
printf("\nv=%d,s1=%d,s2=%d,s3=%d\n",v,s1,s2,s3);
}
【例8.14】外部变量与局部变量同名。
inta=3,b=5; /*a,b为外部变量*/
max(inta,intb)/*a,b为外部变量*/
{intc;
c=a>b?
a:
b;
return(c);
}
main()
{inta=8;
printf("%d\n",max(a,b));
}
如果同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即它不起作用。
8.9 变量的存储类别
8.9.1动态存储方式与静态动态存储方式
前面已经介绍了,从变量的作用域(即从空间)角度来分,可以分为全局变量和局部变量。
从另一个角度,从变量值存在的作时间(即生存期)角度来分,可以分为静态存储方式和动态存储方式。
静态存储方式:
是指在程序运行期间分配固定的存储空间的方式。
动态存储方式:
是在程序运行期间根据需要进行动态的分配存储空间的方式。
用户存储空间可以分为三个部分:
1) 程序区;
2) 静态存储区;
3) 动态存储区;
全局变量全部存放在静态存储区,在程序开始执行时给全局变量分配存储区,程序行完毕就释放。
在程序执行过程中它们占据固定的存储单元,而不动态地进行分配和释放;
动态存储区存放以下数据:
1) 函数形式参数;
2) 自动变量(未加static声明的局部变量);
3) 函数调用实的现场保护和返回地址;
对以上这些数据,在函数开始调用时分配动态存储空间,函数结束时释放这些空间。
在c语言中,每个变量和函数有两个属性:
数据类型和数据的存储类别。
8.9.2auto变量
函数中的局部变量,如不专门声明为static存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。
函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量),都属此类,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。
这类局部变量称为自动变量。
自动变量用关键字auto作存储类别的声明。
例如:
intf(inta) /*定义f函数,a为参数*/
{autointb,c=3; /*定义b,c自动变量*/
……
}
a是形参,b,c是自动变量,对c赋初值3。
执行完f函数后,自动释放a,b,c所占的存储单元。
关键字auto可以省略,auto不写则隐含定为“自动存储类别”,属于动态存储方式。
8.9.3用static声明局部变量
有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,这时就应该指定局部变量为“静态局部变量”,用关键字static进行声明。
【例8.15】考察静态局部变量的值。
f(inta)
{autob=0;
staticc=3;
b=b+1;
c=c+1;
return(a+b+c);
}
main()
{inta=2,i;
for(i=0;i<3;i++)
printf("%d",f(a));
}
对静态局部变量的说明:
1) 静态局部变量属于静态存储类别,在静态存储区内分配存储单元。
在程序整个运行期间都不释放。
而自动变量(即动态局部变量)属于动态存储类别,占动态存储空间,函数调用结束后即释放。
2) 静态局部变量在编译时赋初值,即只赋初值一次;而对自动变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
3) 如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。
而对自动变量来说,如果不赋初值则它的值是一个不确定的值。
【例8.16】打印1到5的阶乘值。
intfac(intn)
{staticintf=1;
f=f*n;
return(f);
}
main()
{inti;
for(i=1;i<=5;i++)
printf("%d!
=%d\n",i,fac(i));
}
8.9.4register变量
为了提高效率,C语言允许将局部变量得值放在CPU中的寄存器中,这种变量叫“寄存器变量”,用关键字register作声明。
【例8.17】使用寄存器变量。
intfac(intn)
{registerinti,f=1;
for(i=1;i<=n;i++)
f=f*i
return(f);
}
main()
{inti;
for(i=0;i<=5;i++)
printf("%d!
=%d\n",i,fac(i));
}
说明:
1) 只有局部自动变量和形式参数可以作为寄存器变量;
2) 一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量;
3) 局部静态变量不能定义为寄存器变量。
8.9.5用extern声明外部变量
外部变量(即全局变量)是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。
如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了。
如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”。
表示该变量是一个已经定义的外部变量。
有了此声明,就可以从“声明”处起,合法地使用该外部变量。
【例8.18】用extern声明外部变量,扩展程序文件中的作用域。
intmax(intx,inty)
{intz;
z=x>y?
x:
y;
return(z);
}
main()
{externA,B;
printf("%d\n",max(A,B));
}
intA=13,B=-8;
说明:
在本程序文件的最后1行定义了外部变量A,B,但由于外部变量定义的位置在函数main之后,因此本来在main函数中不能引用外部变量A,B。
现在我们在main函数中用extern对A和B进行“外部变量声明”,就可以从“声明”处起,合法地使用该外部变量A和B。
对于malloc而来的变量存储在堆(heap)中,局部变量都存储在栈(stack)中。
堆和栈的区别:
堆和栈的区别一个由c/C++编译的程序占用的内存分为以下几个部分1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。
其操作方式类似于数据结构中的栈。
2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
-程序结束后有系统释放4、文字常量区—常量字符串就是放在这里的。
程序结束后由系统释放5、程序代码区—存放函数体的二进制代码。
在全局变量和全局静态变量有什么区别:
在全局变量和全局静态变量有什么区别变量可以分为:
全局变量、静态全局变量、静态局部变量和局部变量。
按存储区域分,全局变量、静态全局变量和静态局部变量都存放在内存的静态存储区域,局部变量存放在内存的栈区。
按作用域分,全局变量在整个工程文件内都有效;静态全局变量只在定义它的文件内有效;静态局部变量只在定义它的函数内有效,只是程序仅分配一次内存,函数返回后,该变量不会消失;局部变量在定义它的函数内有效,但是函数返回后失效。
全局变量和静态变量如果没有手工初始化,则由编译器初始化为0。
局部变量的值不可知。
静态全局变量,只本文件可以用。
全局变量是没有定义存储类型的外部变量,其作用域是从定义点到程序结束.省略了存储类型符,系统将默认为是自动型.静态全局变量是定义存储类型为静态型的外部变量,其作用域是从定义点到程序结束,所不同的是存储类型决定了存储地点,静态型变量是存放在内存的数据区中的,它们在程序开始运行前就分配了固定的字节,在程序运行过程中被分配的字节大小是不改变的.只有程序运行结束后,才释放所占用的内存.自动型变量存放在堆栈区中.堆栈区也是内存中一部分,该部分内存在程序运行中是重复使用的.声明变量与定义变量有什么区别声明是向编译器介绍名字--标识符。
它告诉编译器“这个函数或变量在某处可找到,它的模样象什么”。
而定义是说:
“在这里建立变量”或“在这里建立函数”。
它为名字分配存储空间。
无论定义的是函数还是变量,编译器都要为它们在定义点分配存储空间。
对于变量,编译器确定变量的大小,然后在内存中开辟空间来保存其数据,对于函数,编译器会生成代码,这些代码最终也要占用一定的内存。
在C和C++中,可以在不同的地方声明相同的变量和函数,但只能有一个定义(有时这称为ODR,单一定义规则)。
。
。
定义也可以是声明,如果有intx;,之前编译器未发现标识符x,编译器则把这一标识符看成是定义并立即为它分配存储空间。
。
。
。
。
。
对“变量声明”的解释向来模糊且自相矛盾。
。
。
函数声明包括函数类型、函数名、参数列表和一个分号,这些信息足以编译器认出它是一个函数声明并可识别出这个函数的外部特征。
由此推断,变量声明应是类型标识后面跟一个标识符。
如inta;但这产生了一个矛盾,这段代码有足够的信息让编译器为之分配存储空间,而且编译器也确实给之分配了存储空间。
要解决这个问题,对于C和C++需要一个关键字来说明“这是一个声明,它的定义在别的地方”,这个关键字就是extern,它表示变量是在文件以外定义的,或在文件后面定义的。
在变量定义前加extern表示声明一个变量但不定义它,如:
externinta;extern也可用于函数声明,如:
externintfunc1(intlength,intwidth);但由于没有函数体,编译器必把它当成声明而非定义,extern对于函数来说是多余的、可选的。
C语言的设计者并不要求函数声明使用extern,这可能有些令人遗憾,如果函数声明也要求用extern,那么形式上与变量声明更加一致了,从而减少了混乱(但这就需要更多的输入,这也许能解释为什么不要求函数声明使用extern的原因)。
。
。
什么是字节对齐,为什么要对齐?
现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
对齐的作用和原因:
各个硬件平台对存储空间的处理上有很大的不同。
一些平台对某些特定类型的数据只能从某些特定地址开始存取。
比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。
比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。
显然在读取效率上下降很多。
在C语言里面,局部变量,全局变量都是存贮在栈(stack)里面的,
而所有用malloc和new这种操作符动态分配的空间则都是存贮在堆(dump)里面的,
举个简单的例子:
int*ptr;
ptr=(int*)malloc(100*sizeof(int));
这两句中,ptr这个指针变量是存贮在栈里面,但是他所指向的内容则是在堆里面。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 局部 变量 全局变量 在内 中的 存放 位置
![提示](https://static.bdocx.com/images/bang_tan.gif)