各类变量

转自:http://www.cnblogs.com/hnrainll/archive/2011/08/26/2155079.html

C语言中局部变量和全局变量变量的存储类别(static,extern,auto,register)

 

局部变量和全局变量

在 讨论函数的形参变量时曾经提到,形参变量只在被调用期间才分配内存单元,调用结束立即释放。这一点表明形参变量只有在函数内才是有效的,离开该函数就不能 再使用了。这种变量有效性的范围称变量的作用域。不仅对于形参变量,C语言中所有的量都有自己的作用域。变量说明的方式不同,其作用域也不同。C语言中的 变量,按作用域范围可分为两种,即局部变量和全局变量。

8.8.1 局部变量

局部变量也称为内部变量。局部变量是在函数内作定义说明的。其作用域仅限于函数内,离开该函数后再使用这种变量是非法的。

例如:

int f1(int a)        /*函数f1*/

{

int b,c;

……

}

a,b,c有效

int f2(int x)        /*函数f2*/

{

int y,z;

……

}

x,y,z有效

main()

{

int m,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()

{

int s,a;

……

{

int b;

s=a+b;

……                 /*b作用域*/

}

……                   /*s,a作用域*/

}

【例8.12】

main()

{

int i=2,j=3,k;

k=i+j;

{

int k=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。但在一个函数之前定义的全局变量,在该函数内使用可不再加以说明。

例如:

int a,b;          /*外部变量*/

void f1()         /*函数f1*/

{

……

}

float x,y;         /*外部变量*/

int fz()          /*函数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的面积。

int s1,s2,s3;

int vs( int a,int b,int c)

{

int v;

v=a*b*c;

s1=a*b;

s2=b*c;

s3=a*c;

return v;

}

main()

{

int v,l,w,h;

printf("\ninput length,width and height\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】外部变量与局部变量同名。

int a=3,b=5;     /*a,b为外部变量*/

max(int a,int b) /*a,b为外部变量*/

{int c;

c=a>b?a:b;

return(c);

}

main()

{int a=8;

printf("%d\n",max(a,b));

}

如果同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即它不起作用。

8.9   变量的存储类别

8.9.1 动态存储方式与静态动态存储方式

前面已经介绍了,从变量的作用域(即从空间)角度来分,可以分为全局变量和局部变量。

从另一个角度,从变量值存在的作时间(即生存期)角度来分,可以分为静态存储方式和动态存储方式。

静态存储方式:是指在程序运行期间分配固定的存储空间的方式。

动态存储方式:是在程序运行期间根据需要进行动态的分配存储空间的方式。

用户存储空间可以分为三个部分:

1)       程序区;

2)       静态存储区;

3)       动态存储区;

全局变量全部存放在静态存储区,在程序开始执行时给全局变量分配存储区,程序行完毕就释放。在程序执行过程中它们占据固定的存储单元,而不动态地进行分配和释放;

动态存储区存放以下数据:

1)       函数形式参数;

2)       自动变量(未加static声明的局部变量);

3)       函数调用实的现场保护和返回地址;

对以上这些数据,在函数开始调用时分配动态存储空间,函数结束时释放这些空间。

在c语言中,每个变量和函数有两个属性:数据类型和数据的存储类别。

8.9.2 auto变量

函数中的局部变量,如不专门声明为static存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量),都属此类,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。这类局部变量称为自动变量。自动变量用关键字auto作存储类别的声明。

例如:

int f(int a)         /*定义f函数,a为参数*/

{auto int b,c=3;     /*定义b,c自动变量*/

……

}

a是形参,b,c是自动变量,对c赋初值3。执行完f函数后,自动释放a,b,c所占的存储单元。

关键字auto可以省略,auto不写则隐含定为“自动存储类别”,属于动态存储方式。

8.9.3 用static声明局部变量

有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,这时就应该指定局部变量为“静态局部变量”,用关键字static进行声明。

【例8.15】考察静态局部变量的值。

f(int a)

{auto b=0;

static c=3;

b=b+1;

c=c+1;

return(a+b+c);

}

main()

{int a=2,i;

for(i=0;i<3;i++)

printf("%d",f(a));

}

对静态局部变量的说明:

1)     静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动态存储空间,函数调用结束后即释放。

2)     静态局部变量在编译时赋初值,即只赋初值一次;而对自动变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。

3)     如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值则它的值是一个不确定的值。

【例8.16】打印1到5的阶乘值。

int fac(int n)

{static int f=1;

f=f*n;

return(f);

}

main()

{int i;

for(i=1;i<=5;i++)

printf("%d!=%d\n",i,fac(i));

}

8.9.4 register变量

为了提高效率,C语言允许将局部变量得值放在CPU中的寄存器中,这种变量叫“寄存器变量”,用关键字register作声明。

【例8.17】使用寄存器变量。

int fac(int n)

{register int i,f=1;

for(i=1;i<=n;i++)

f=f*i

return(f);

}

main()

{int i;

for(i=0;i<=5;i++)

printf("%d!=%d\n",i,fac(i));

}

说明:

1)       只有局部自动变量和形式参数可以作为寄存器变量;

2)       一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量;

3)       局部静态变量不能定义为寄存器变量。

8.9.5 用extern声明外部变量

外部变量(即全局变量)是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了。如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”。表示该变量是一个已经定义的外部变量。有了此声明,就可以从“声明”处起,合法地使用该外部变量。

【例8.18】用extern声明外部变量,扩展程序文件中的作用域。

int max(int x,int y)

{int z;

z=x>y?x:y;

return(z);

}

main()

{extern A,B;

printf("%d\n",max(A,B));

}

int A=13,B=-8;

说明:在本程序文件的最后1行定义了外部变量A,B,但由于外部变量定义的位置在函数main之后,因此本来在main函数中不能引用外部变量A,B。现在我们在main函数中用extern对A和B进行“外部变量声明”,就可以从“声明”处起,合法地使用该外部变量A和B。

时间: 2024-10-14 12:31:55

各类变量的相关文章

各类变量生存周期及存储空间

一.运行时环境简介 程序在执行期间,将在其自己的逻辑地址空间内运行,其中每个程序值都在这个空间内有一个地址.一种典型的程序空间模式如下图: 首先,运行时的数据包含数据区和代码区.图中的Text就是代码区,存储目标代码.数据区包括图中的Data.BSS.Heap和Stack. 1.(常量区)Data区主要存储常量数据,主要是需要较多空间的常量,如 char s[32]="Hello World":中的"Hello World". 2.(全局区)BSS主要存储全局和静态

C变量类型和作用域

C语言中所有变量都有自己的作用域,申明变量的类型不同,其作用域也不同.C语言中的变量,按照作用域的范围可分为两种, 即局部变量和全局变量. 一.局部变量 局部变量也称为内部变量.局部变量是在函数内作定义说明的.其作用域仅限于函数内, 离开该函数后再使用这种变量是非法的. 例如: int f1(int a) /*函数f1*/ {     int b,c: ……} int f2(int x) /*函数f2*/ {     int y,z;: ……} f1内定义了三个变量,a为形参,b,c为一般变量.

C语言中变量的存储类型

在C语言中,对变量的存储类型说明有以下四种: auto 自动变量register   寄存器变量extern 外部变量static   静态变量 自动变量和寄存器变量属于动态存储方式,外部变量和静态变量属于静态存储方式. 在介绍了变量的存储类型之后,可以知道对一个变量的说明不仅应说明其数据类型,还应说明其存储类型. 因此变量说明的完整形式应为:存储类型说明符数据类型说明符变量名,变量名-:例如: static int a,b;      说明a,b为静态类型变量 auto char c1,c2;

第5章 进程环境(5)_非局部跳转

6. 非局部跳转 (1)setjmp和longjmp语句 头文件 #include<setjmp.h> 函数 int* setjmp(jum_buf env); 返回值 直接调用返回0,若从longjmp调用返回则返回非0值 功能 设置非局部跳转的跳转点   函数 void longjmp(jmp_buf env, int val); 功能 进行非局部转转,val为返回值 参数 env:一个特殊类型jmp_buf.这一数据类型是某种形式的数组,其中存放在调用longjmp时能用来恢复栈状态的信

Linux后台开发面试问题汇总

个人从事安全后台开发,当然是linux环境下的了.举几个常见的问题.1. 数据结构基础.比如实现一个最简单的哈希表.2. 操作系统基础.linux进程模型,堆/栈的区别,大概的位置,各往哪个方向生长,各类变量存储在哪些区域:更深一点可能会问动态库与静态库的区别,因为这个在生产环境中常见,动态库映射在进程模型的哪里.其他常见如僵尸进程.线程共享等问题.3. tcp/ip基础.比如常问三次握手,四次挥手,为什么要四次:time_wait状态相关问题:mtu分片问题.现在一般不会问tcp/ip头大小这

微信&#183;小程序开发工具安装指南及注意事项

这两天闲来无事,也安装了 “微信折叠”的开发工具来玩一下.以下是一些小道消息及使用体验,过两天我会写一篇文章以开发者的角度来详细评价微信小程序: 微信小程序不能开发游戏类.直播类功能,小程序每个人关注的上限是20个(还不确定,不过我相信这是真的,这次公布的API里并没有视频组件.微信太大,苹果要有所顾忌,但是微信也要做出相应的让步) 微信目前有没有同苹果商谈好,还是个未知数,毕竟会对AppStore有一定的冲击. 抛弃了大量的javascript组件后,这个生态体系变得相当的封闭,微信解释肯定是

日志级别

log4j可以通过配置来确定某个category的输出级别level, 共有四种, 级别从低到高分别是:debug -> info -> error -> fatel.日志输出的时候, 只会输出大于等于该级别的日志, 也就是设置了INFO之后, DEBUG是不会被输出, 只会输出INFO.ERROR和FATAL级别的日志.但即使日志关闭了, 日志的语句还是会被执行的(只是不输出而已), 因此日志的参数还是会构造, 例如logger.debug(buildLongString()), 虽然

C#基本线程同步

0 概述 所谓同步,就是给多个线程规定一个执行的顺序(或称为时序),要求某个线程先执行完一段代码后,另一个线程才能开始执行. 第一种情况:多个线程访问同一个变量: 1. 一个线程写,其它线程读:这种情况不存在同步问题,因为只有一个线程在改变内存中的变量,内存中的变量在任意时刻都有一个确定的值: 2. 一个线程读,其它线程写:这种情况会存在同步问题,主要是多个线程在同时写入一个变量的时候,可能会发生一些难以察觉的错误,导致某些线程实际上并没有真正的写入变量: 3. 几个线程写,其它线程读:情况同2

关于代码调试de那些事

原文出处:http://www.wklken.me/posts/2014/11/23/how-to-debug.html 关于代码调试de那些事 1.你得明白你在做什么, 保持清醒 2.想清楚了再写代码 3.关于脚手架代码 4.写完一段代码第一时间自己review一下 5.review中注意, 代码是抠过来的么? 6.搞明白问题的表现是什么(症状) 7.调试过程中, 需要时刻注意 8.环境/数据一致性 9.先不要动代码, 假设代码是正确的 10.首先要怀疑自己 11.对于莫名其妙的问题, 多试几