6.11 对局部变量的进一步修饰
对于局部变量,定义的位置向编译器说明了这个变量可以被使用的代码范围,定义的类型向编译器明确的是该变量的存储空间和运算规则,但是局部变量还有另一个属性——就是它的生命周期。有的局部变量是从程序运行一开始就存在,一直到程序运行结束才消失的;有的则是在被使用时才存在,不使用时就消失——把所占据的内存还给操作系统去做其他的事情。这两类局部变量的性质是不同的,在程序中起的作用也不同。需要用进一步的修饰来供编译器加以区别对待。
这类修饰符号也由相应的关键字担任,称之为变量存储类别说明符。
6.11.1 几乎一直是摆设的关键字——auto
auto这个关键字在C语言中一直是个摆设,原因是auto是局部变量的默认修饰。也就是说,如果局部变量前不加任何存储类别说明符,那么这个局部变量就是auto类别的。前面用到的所有局部变量都是auto类别的。
auto类别的局部变量的含义是在用到这个局部变量时,“自动”地为它找个存储空间,离开它的作用范围后,它所占据的空间自动地还给计算机。这里所谓的不再用到是指,这个局部变量所在的代码模块已经被执行完了。当程序再次开始执行auto类别的局部变量所在的代码模块中的代码时,会再次为这个变量寻找一个存储空间,基本上这个空间和上一次它所占据的空间是不一样的,即使一样也毫无意义,因为原来所占据的内存空间既然还给了操作系统,那么里面的内容——原来的值,可能早就面目全非了。
这段程序的运行结果是:
这表明了每次运行到j所在的代码模块时,都为j寻找存储空间并且重新为j赋初值1。而且每次离开j所在的代码模块时,j的内存都被释放掉。
形参的性质是一样的,形参也是在被调用时才拥有自己的存储空间,在return时这个空间被释放掉。
6.11.2 static类别的局部变量
和auto类别的局部变量相反,static类别的局部变量是在程序开始执行的时候就存在的,而且它的生命一直持续到程序的结束。下面的代码和程序的输出结果演示了static类别局部变量与auto类别局部变量的重要区别。
这段程序的运行结果是:
对于static类别的局部变量,定义时赋初值的含义与auto类别定义时赋初值完全不同。由于static类别的局部变量在程序运行期间一直存在,所以初值也是在程序刚刚运行时就存在了,以后将不再执行赋初值这个动作。而对于auto类别的局部变量,所在代码模块被执行几次,赋初值的动作就执行了几次,因为auto局部变量一直处于不断的生生死死的状态中,每次重生都得为它赋初值。
如果在定义时没有指定初值,则对于static类别的局部变量来说初始值是“0”(各种类型的0);而对于auto类别的局部变量来说初始值是“垃圾值”,没有意义且事先也没人知道究竟会是多少。
形参不可以是static类别的,这在概念上那是自相矛盾的。因为形参必须在函数调用时,才能把实参的值作为自己的初值。
此外需要注意的是,尽管staitc局部变量在程序运行期间一直都存在,但这并不意味着这个变量在代码中哪里都可以使用。staitc局部变量依然只在自己所在的代码模块中可以使用。“static”是程序运行时间上的概念,而“局部”是代码空间中的概念。
还要特别注意的是,对于递归调用,staitc局部变量不再是每次调用都有一个“副本”,而是唯一的。