在C语言的学习过程中,会涉及到局部变量和全局变量的内存分配和内存释放问题
本文先介绍全局变量和局部变量,
全局变量和局部变量
程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量,外部变量是全局变量(也称全程变量)。全局变量可以为本文件中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束。
(1)主函数中定义的变量(局部变量)也只在主函数中有效。主函数也不能使用其他函数中定义的变量。
(2) 不同函数中可以使用同名的变量,它们代表不同的对象,互不干扰。
#include <stdio.h>
int a=8;
int main()
{
int a=5;
printf("%d",a);
}
输出结果:5
注:在函数中定义了和全局变量同名的变量,在此范围内全局变量a被局部变量a屏蔽,相当于全局变量a在此范围内不存在(即它不起作用)
变量的存储
1.存储方式
从变量值存在的时间(即生存期)来观察,有的变量在程序运行的整个过程都是存在的,而有的变量则是在调用其所在的函数时才临时分配存储单元,而在函数调用结束后该存储单元就马上释放了,变量不存在了。
变量的存储有两种不同的方式: 静态存储方式和动态存储方式。
静态存储方式是指在程序运行期间由系统分配固定的存储空间的方式。
动态存储方式则是在程序运行期间根据需要进行动态的分配存储空间的方式
全局变量全部存放在静态存储区中,在程序开始执行时给全局变量分配存储区,程序执行完毕就释放。在程序执行过程中它们占据固定的存储单元,而不是动态地进行分配和释放。
在动态存储区中存放以下数据:
- 函数形式参数。在调用函数时给形参分配存储空间。
- 函数中定义的没有用关键字static声明的变量,即自动变量。
- 函数调用时的现场保护和返回地址等。
对于动态存储的数据,在函数调用开始时分配动态存储空间,函数结束时释放这些空间。在程序执行过程中,这种分配和释放是动态的,如果在一个程序中两次调用同一函数,而在此函数中定义了局部变量,在两次调用时分配给这些局部变量的存储空间的地址可能是不相同的。
如果一个程序中包含若干个函数,每个函数中的局部变量的生存期并不等于整个程序的执行周期,它只是程序执行周期的一部分。在程序执行过程中,先后调用各个函数,此时会动态地为局部变量分配和释放存储空间。
存储类别
在C语言中,每一个变量和函数都有两个属性: 数据类型和数据的存储类别。
存储类别指的是数据在内存中存储的方式(如静态存储和动态存储)。
C的存储类别包括4种: 自动的(auto)、静态的(statis)、寄存器的(register)、外部的(extern)。根据变量的存储类别,可以知道变量的作用域和生存期。
在定义和声明变量和函数时,一般应同时指定其数据类型和存储类别,也可以采用默认方式指定(即如果用户不指定,系统会隐含地指定为某一种存储类别)。 常见的自动变量就是省略了auto
例如 auto int a;等价于int a;
这里只简单的介绍一下存储类别,具体的类别之后的笔记再涉及
静态局部变量
- 静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,分配在动态存储区空间而不在静态存储区空间,函数调用结束后即释放。
- 对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。而对自动变量赋初值,不是在编译时进行的,而是在函数调用时进行的,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
- 如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符′\0′(对字符变量)。而对自动变量来说,它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的内容是不可知的。
- 虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的。因为它是局部变量,只能被本函数引用,而不能被其他函数引用。
这里提到了静态局部变量在编译时赋初值。
可以看到Dev C++中存在编译这个功能,这里简单介绍一下编译的作用:
C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接。编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程。链接是把目标文件、操作系统的启动代码和用到的库文件进行组织形成最终生成可执行代码的过程。 编译分为四个阶段:预处理、编译、汇编、链接。生成可执行代码后即可点击运行执行程序
具体的编译可以参考此文章C语言文件的编译与执行的四个阶段以及C代码是如何变成程序的
如果在编译时出现错误,就不会生成可执行文件看到这样一句话:全局变量必须在程序开始运行时初始化完成,因此初始值必须保证保存在编译生成的可执行文件中,所以初始值必须在编译时计算出来。