“天地玄黄,宇宙洪荒”,先有天地,之后方有古今。
变量同是,先有变量的作用域(存在的地点),然后出现了变量的生存期(存在的时间)。
【变量存储的方式】
首先变量实际上是存放到两个区域的:
- 静态存储区:是指在程序运行区间由系统分配固定的存储空间的方式。
- 动态存储区:程序运行期间根据需要动态的分配存储空间。
【变量分类】
- 局部变量:在[函数]内部声明的变量。
【作用域】:从定义变量的位置到本函数结束。
<1>自动变量(auto变量),即动态局部变量,不专门声明为static的变量。
分类:<11>函数形参;
<12>函数中定义的变量;
<13>函数调用的现场保护和返回地址;
存放位置:动态存储区;
【生存期】:调用函数时,赋初值生存,结束调用死亡。
<2>静态局部变量(static局部变量),通过static声明;
存放位置:静态存储区;
【生存期】:调用函数时,赋初值生存,结束调用继续存在
【缺点】:长期占用不释放,多占内存,不建议多使用。
<3>寄存器变量(register变量),通过register声明;
存放位置:寄存器(寄存器的访问速度超过内存访问速度);
【生存期】:同静态局部变量,较少见。 - 全局变量(外部变量):在[函数]之外定义的变量。
【生存期】:存在于程序的整个运行中。
【作用域】:从定义变量的位置到本函数结束。
【作用域扩展】
<1>在定义变量之前可以访问,在声明变量之前如果想要对该变量进行操作,可以使用extern,如:
extern int a;
a++;
int a; //这个定义必须是外部变量定义
<2>在其他文件中可以访问,在其他文件中使用本文件的变量时必须加上extern。
在遇到extern时,编译器先从本文件中查找是否有外部变量的定义,如果没有再从其他文件中查找外部变量的定义。
<3>将外部变量作用域限制在本文件中(默认的外部变量定义后在其他文件中都是可查的),现在我们不想在其他文件中可以访问本文件的变量,可以在变量前声明static,这样作用域就限制在本文件中了。
[在main函数中定义变量是局部还是全局的]
是局部变量,任何函数内部的变量都是局部的。
【内存中的堆和栈】
- .[内存分区]
<1>栈区:处于相对较高的地址以地址的增长方向为上的话,栈地址是向下增长的。栈中分配[自动变量];
<2>堆区:是向上增长的用于分配程序员申请的内存空间;
<3>静态区:是分配[静态局部变量][全局变量]空间的;
<4>文字常量区:常量字符串就是放在这里的,程序结束后由系统释放。
<5>程序代码区:存放[函数体]的二进制代码。// 来看一个网上很流行的经典例子:main.c int a = 0; 全局初始化区 char *p1; 全局未初始化区 main(){ int b; 栈 char s[] = "abc"; 栈 char *p2; 栈 char *p3 = "123456"; 123456\0在常量区,p3在栈上。 static int c =0; 全局(静态)初始化区 p1 = (char *)malloc(10); 堆 p2 = (char *)malloc(20); 堆 }
- [注释]:
<1>堆是由用户来分配的,用malloc,calloc函数申请,相应的用free来释放,或者用realloc重分配。
注:malloc/calloc/realloc函数的基类型(返回的指针所指的类型)都是void(不确定的)类型,在使用的时候必须类型转换为需要的基类型。内存的动态分配主要用于建立程序中的动态数据结构,如链表。
<2>栈是系统自动分配的,子程序调用时,返回地址压入栈,退出时从栈顶取返回地址。如果在子程序中定义局部变量,这些变量就分配在栈上,用来了,子程序退出的时候退栈,局部变量就失效。void sub() { int a[100]; // 局部变量,分配在栈上,退出子程序自动释放。 int *p = (int *)malloc( 100 ); // 分配在堆上,需要用free释放。 }
【变量的声明和定义的关系】
把建立存储空间的声明成为定义(int a=4;),把未建立存储空间的声明成为声明(extern int a;);
【内部函数和外部函数】
函数本质上是外部的,可以被外部的其他函数和外部文件夹中的文件所访问。
- 内部函数
我们不希望函数被外部文件夹的文件访问,所以我们我们使用static修饰当前函数。就只能在本文件中访问。 - 外部函数
函数在外部文件访问是有条件的,即在定义该函数的时候在前面加上extern,这样我们可以在本文件所在文件夹下的其他函数中对该函数进行具体的实现,include就是采用这种方法,导入一个大类库,我们可以调用类库中的函数.