从变量的存储机制来看,C 语言的变量可分为动态存储变量与静态存储变量。
变量按存储机制的分类
动态存储:程序在运行期间根据需要动态分配内存的存储方式。
静态存储:程序在运行开始就分配固定内存的存储方式。
就C 程序运行的内存来说,大致可分为3个部分:程序区,静态存储区(在运行开始就分配固定内存,直到程序运行结束才会释放内存),动态存储区(运行期间根据需要动态分配内存)。C 的变量,要么放在静态存储区,要么放在动态存储区。
静态存储区存放什么样的变量?
存放2类变量:全局变量和 static 修饰的局部变量。
不管是那种外部变量,外部全局变量或者内部全局变量(static 修饰的,只在当前源文件中有效的全局变量),都存放在静态存储区的。
动态存储区存放什么样的数据?
主要存放3类数据:函数的形参变量;非 static 的局部变量;函数执行的现场数据以及返回地址等。
可以在定义变量时指定变量的存储类别,C语言支持如下几种存储类别。
- auto: 指定该变量采用自动存储机制——局部变量默认采用这种方式,对定义局部变量,auto 关键字可以忽略。
- static:指定局部变量存到静态存储区。这样该变量所占空间会一直保存到程序退出。
- register:指定该变量存放到寄存器内。
- extern:用于声明外部变量。
静态局部变量和普通局部变量的区别
示例代码:
#import <Foundation/Foundation.h>
void fac(int n)
{
auto int a = 1;
// 定义静态局部变量,每次函数调用结束后,都会保存该变量的值
static int b = 1;
// a(每次调用时a总是等于1)的值加上n
a += n;
// b(b变量可以保留上一次调用的结果)的值加上n
b += n;
NSLog(@"a的值为:%d , b的值为%d" , a , b);
}
int main(int argc , char * argv[])
{
@autoreleasepool{
// 采用循环调用了fac()函数4次
for(int i = 0 ; i < 4 ; i++)
{
fac(i);
}
}
}
每次调用 fac() 函数时,变量 a 的值总是1,而对于 static 修饰的变量而言,只有第一次调用该函数的时候才会等于初始值,以后该变量都会保存改动后的结果。
贴士:
实际上,程序员也可以不对 static 变量指定初始值,那么系统会在编译时自动为 static 变量分配默认的初始值。默认初始值都是广义的0.对整型 static 局部变量,该初始值总是0;对于浮点型的 static 局部变量,初始值总是0.0;对于指针型的 static 局部变量,初始值总是0x0(未指向任何有效对象的指针)
利用 static 变量的特性,轻松计算阶乘。代码如下:
#import <Foundation/Foundation.h>
int fac(int n)
{
// static变量,第一次运行时该变量的值为1
// f可以保留上一次调用函数的结果
static int f = 1;
f = f * n;
return f;
}
int main(int argc , char * argv[])
{
@autoreleasepool{
// 采用循环,控制调用该函数7次
for(int i = 1 ; i < 8 ; i++)
{
NSLog(@"%d的阶乘为:%d", i , fac(i));
}
}
}
特别指出:
虽然静态局部变量可以在函数调用结束后仍然在,但只能在本函数在此调用时访问该变量的值,其他函数不能访问该静态局部变量的值。
什么时候使用静态局部变量?
应该慎重使用静态局部变量,因为静态局部变量会一直占据固定的内存。考虑使用静态局部变量的情况如下:
- 需要变量能保留上次调用结束时的值。
- 希望变量只被初始化一次,以后只是被引用,而不希望对其重新赋值。