存储方式
C语言根据变量的生存周期来区分,分为静态存储方式和动态存储方式。
- 静态存储方式:在程序运行期间分配固定存储空间的方式。静态存储区存放了在整个程序执行过程中都存在的变量,如全局变量。
- 动态存储方式:在程序运行期间根据需要进行动态的分配存储空间的方式。动态存储区中存放的变量是根据程序运行的需要而建立和释放的,通常包括:函数形式参数、自动变量、函数调用时的现场保护和返回地址等。
在内存中的用户存储空间分为:程序区、静态存储区、动态存储区。
存储类别
C语言中的存储类别分为四类:自动(auto)、静待(static)、寄存器(register)、外部的(extern)。
1、auto 自动变量 --局部变量
auto定义的变量为自动变量,auto可以省略,auto不写则隐含定为“自动存储类别”,属于动态存储方式。
函数的形参、在函数中定义的局部变量(包含在符合语句中定义的局部变量),都是自动变量auto。存储在内存的动态存储区中。
int funny (int a) { /*定义函数,a为参数/形参*/
auto int b ,c; /*定义b,c自动变量*/
/*....*/
}
2、static 静态变量
static修饰的是静态变量,如果定义在函数内部,称之为静态局部变量;如果定义在函数外部,称之为静态外部变量。
静态变量都存储于静态存储区。
- 静态局部变量
1、静态局部变量在编译时赋初值,第一次赋值有效,以后在调用时,直接使用上一次调用的值而不需要重新赋值。
2、静态局部变量属于静态存储类别,在静态存储区内分配存储单元,在程序整个运行期间都不释放。
3、如果在定义局部变量时不赋初值的话,则静态变量在编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。
void funny (int a) {
static int index = 1;
index += 1;
printf("funny :%d\n",index);
}
int main(int argc, const char * argv[]) {
for (int i = 0; i < 5; i ++) {
funny(10);
}
printf("********\n");
funny(0);
return 0;
}
打印结果:
funny :2
funny :3
funny :4
funny :5
funny :6
********
funny :7
- 静态外部变量/静态全局变量
全局变量都是放在静态存储区中的。一般来说,外部变量是在函数外定义的全局变量,它的作用域是从变量定义处开始,到本程序文件末尾。
静态外部变量,是为了使某些变量只限于被本文件引用,而不能被其他文件引用。
1、static int a,变量只可以在当前文件中使用,
2、int a,只是全局变量,可以在整个工程中使用,其他文件引用时需要extern关键字声明
test.c
static int staticInt_test = 100;
int pInt_test = 200;
/*-----------------------*/
main.c
int main(int argc, const char * argv[]) {
extern int pInt_test;/*可以通过extern关键字声明,之后可以直接使用test.c中声明的变量 */
printf("test:%d\n",pInt_test); /*打印结果:200*/
extern int staticInt_test ;/*如果声明的是全局静态变量,这里在编译时会报错,找不到对应变量。*/
printf("test static:%d\n",staticInt_test); /* 报错 */
return 0;
}
static对局部变量和全局变量的作用不同,对局部变脸来说它使变量由动态存储方式改为静态存储方式。对全局变量来说,它使变量局部化(局部于本文件),但仍为静态存储方式。
从作用域角度看,凡有static声明的,其作用域都是局限的,或者都是局限于本函数内(静态局部变量),或者局限于本文件内(静态外部变量)。
3、register 寄存器变量
为提高效率,C语言允许将局部变量的值放在CPU的寄存器中,这种变量叫“寄存器变量”,关键字register声明。
void funny () {
register int i,sum = 0;//定义为寄存器变量
}
只有局部自动变量和形式参数可以作为寄存器变量;一个计算机系统中的寄存器数据有限,不能定义任意多个寄存器变量,局部静态变量不能定义为寄存器变量。
4、extern 外部变量
extern声明的变量是外部变量,表示把该变量的作用域扩展到此位置。外部变量的含义是某函数可以调用在该函数之后定义的变量。也可以调用其他文件中声明的外部变量。
- 在一个文件内扩展外部变量的作用域
int main(int argc, const char * argv[]) {
extern int count;
printf("%d\n",count);
return 0;
}
int count = 100;
打印结果:
100
/** 如果不作声明,将报错"Use of undeclared identifier 'count'" **/
- 将外部变量的作用域扩展到其他文件,即在一个文件中引用另一个文件已经定义的外部变量
test.c
int pInt_test = 200;
/*-----------------------*/
main.c
int main(int argc, const char * argv[]) {
extern int pInt_test;
/*通过extern关键字声明,之后可以直接使用test.c中声明的变量 */
printf("test:%d\n",pInt_test);
/*打印结果:200*/
return 0;
}
-
作用
1、在一个文件中扩展外部变量的作用域
2、在一个文件中引用给另一个文件中已经定义的外部变量。
部分概念说明
数据存放的6中形式:
- 1、程序代码区--存放程序编译后的可执行代码
- 2、静态区(全局区)--全局变量和静态变量的存储是放在一起的,初始化的全局变量和初始化的静态变量在同一区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放
- 3、常量区--常量存放位置,程序结束后由系统释放
- 4、堆区--一般由程序分配和释放,如果程序不释放,程序结束时可能由操作系统回收(程序不正常结束则无法回收)
- 5、栈区--由编译器自动分配并且释放,一般存放函数的参数、局部变量等
- 6、寄存器区--有限容量的高速存储区,直接建立在中央处理器内部,用来暂存指令、数据和地址,一般用来保存栈顶指针、指令指针和现在正在被运行的指令。由于存储区其实是在中央处理器内部建立,不在内存中,因此不能将其划分到内存中。这里与内存的功能大致相同,都用来暂存数据。
---这部分说明来自博客
全局变量、局部变量
程序的编译单位是源程序文件,一个原文家可以包含一个或若干个函数。在函数内定义的变量是局部变量,在函数之外定义的变量称为外部变量,外部变量是全局变量(也称全程变量)。
全局变量可以为本文件中其他函数所共用,他的有效范围为从定义变量的位置到本源文件结束。
建议不再必要时不要使用全局变量:1、全局变量在程序执行的全部过程中都占用存储单元,而不是仅在需要时才开辟单元;2、使函数通用性降低;3、全局变量过多,降低程序的清晰性,难以清晰判断出每个瞬间各个外部变量的值。
作用域、生存期
一个变量的属性可以从两个方面分析,一个是作用域,一个事变量值存在时间的长短,即生存期。前者是从空间角度,后者是从时间角度。二者有联系,但不是同一回事。
如果一个变量在某个文件或函数范围内是有效的,就称该范围为该变量的作用域。在该作用域内可以引用该变量。
如果一个变量值在某一时刻是存在的,则认为这一时刻属于该变量的生存期,或称该变量在此时刻存在。
存储类别小结
1、从作用域角度分,有局部变量和全局变量
2、从变量存在的时间(生存期)区分,有动态存储和静态存储两种类型
3、从变量值存储位置区分