根据不同的操作系统,一个进程可能被分配到不同的内存区域去执行,但是不管是什么样的操作系统,什么样的计算机架构,进程使用的内存都可以按照功能大致分为以下4个部分:
(1)代码区:这个区域存储着被装入执行的二进制机器代码,处理器(CPU)会到这个区域取地址并执行
(2)数据区:用于存储全局变量,静态全局变量,静态局部变量,字符串常量等
(3)堆区:进程可以在堆区动态地请求一定大小的内存,并在用完之后归还给堆区,动态分配和回收是堆区的特点
(4)栈区:函数被调用时分配栈区,用于存放函数的参数值,局部变量等值,还要动态地存储函数之间的关系,以保证被调用函数在返回时恢复到被调用函数中继续执行
作用域(可见性)和生存期(局部变量和全局变量)
作用域:标识符能够被使用的范围
只有在作用域内标识符才能被访问,(称为可见性)
变量和函数的可见性针对编译和链接过程,
生存期是针对程序的运行(进程)。当程序没有编译和链接成功,就不要去分析变量和函数的生存期
当函数域内定义的变量名称与块内定义的变量名称同名时
编译器的原则是局部优先原则
#include<stdio.h>
int main()
{
int a=10;
int b=20;
if(10==a)
{
int b=100;
printf("%d\n",b);
}
printf("%d\n",b);
return 0;
}
输出结果如下
对于块中嵌套其他块的情况,如果嵌套块中有同名局部变量,服从局部优先原则,即在内层块中屏蔽外层块中的同名变量
换句话说,内层块中局部变量的作用域为内层块,外层块中局部变量的作用域为外层去除包含同名变量的内层块部分
文件作用域也称全局作用域
#include<stdio.h>
int g_max=10;
int main()
{
int a=10;
int g_max=200;
printf("%d\n",g_max);//局部优先
printf("%d\n",::g_max);//访问全局变量g_max
return 0;
}
如果块内定义的局部变量与全局变量同名,块内依然局部变量优先,但与块作用域不同的是,在块内可以通过域运算符::访问同名的全局变量
域运算符:只适用于全局变量
可见性从另一个角度说明标识符的有效性,可见性与作用域具有一定的一致性。标识符的作用域包含可见范围,可见范围不会超过作用域。
可见性在理解同名标识符的作用域嵌套时十分直观。对于外层块与内层块定义了同名标识符的,在外层作用域中,内层定义的标识符是不可见的,即外层引用的是外层定义的标识符;同样,在内层作用域中,外层的标识符将被内层的同名标识符屏蔽,变得不可见,即外层中同名标识符的可见范围为作用域中挖去内层块的范围
生存期
存储类型决定了变量的生命期,变量生命期指的是从获得空间到空间释放之间的时期(程序的执行过程)
存储类型的说明符有4个:auto,register,static,extern,前两者为自动类型,后两者分别为静态和外部类型
图解局部变量的生存期
在函数内部块中定义的标识符具有局部生命期,其生命期开始于执行到该函数或块的标识符声明处,结束于该函数或块的结束处。具有局部生命期的标识符存放在栈区,具有局部生命期的标识符如果未被初始化,其内容是随机的,不可用。具有局部生命期的标识符必有局部作用域;但反之不然。
图解全局变量的生存期
静态生命期指的是标识符从程序开始运行存在,即具有存储空间,到程序运行结束时消亡,即释放存储空间。
具有静态生命期的标识符存放在静态数据区,属于静态存储类型,如全局变量,静态全局变量,静态局部变量。
具有静态生命期的标识符在未被用户初始化的情况下,系统会自动将其初始化为0
函数驻留在代码区,也具有静态生命期。所有具有文件作用域的标识符都具有静态生命期
图解被static关键字修饰的变量
局部静态变量的作用域为块域,但是生命期为整个文件。
即当块结束时,局部静态变量空间仍然保持,直到整个程序文件结束时该局部静态变量空间才释放,生命期结束
static常见的两种用途
1、统计函数被调用的次数
2、减少局部数组建立和赋值的开销,变量的建立和赋值是需要一定的处理器开销的,特别是数组等含有较多元素的存储类型。在一些含有较多的变量并且被经常调用的函数中,可以将一些数组声明为static类型,以减少减立或者初始化这些变量的开销(主要用途)
写出打印的结果
#include<stdio.h>
#define ARSIZE 10
int *Get_Array()
{
int ar[ARSIZE]={1,2,3,4,5,6,7,8,9,10};
return ar;
}
int main()
{
int *p=Get_Array();
for(int i=0;i<ARSIZE;++i)
{
printf("%d\n",p[i]);
}
return 0;
}
如何解决?
定义成常方法,不可以修改
extern关键字
只能修饰全局变量和函数,不能修饰局部变量,也不能修饰静态局部变量
外部存储类型包括外部变量和外部函数
由多个源程序文件组成的程序中,如果一个文件要使用另外一个文件中定义的全局变量或函数,这些源文件之间通过外部类型的变量和函数进行沟通
在一个文件中定义的全局变量和函数都缺省为外部的,即其作用域可以延伸到程序的其他文件中。但其他文件如果要使用这个文件中定义的全局变量和函数,必须在使用前用extern作为外部声明,外部声明通常放在文件的开头。
变量定义时编译器为其分配存储空间,而变量声明指明该全局变量已在其他地方说明过,编译系统不再分配存储空间,直接使用变量定义时所分配的空间。
函数声明缺省为外部的,因此修饰词extern通常省略
多个文件编译示例