我们的地址空间划分成如下几个区域:
代码区,字符常量区,已初始化全局变量区,未已初始化全局数据区,堆区,栈区;其中有代码区至栈区的代码地址依次增大。
局部变量是具有临时性的局部变量,在栈上开辟
我们在C,C++上malloc时候申请的叫做堆空间,是在堆区开辟的。
我们平时那么定的全局变量可以对所有的函数访问,是因为全局变量在全局数据区。
请问,在这个图当中,我们所展示的这个东西,它是内存吗?
答案是:不是,这个东西其实是地址空间,C,C++程序是以这样的方式分布的。
验证地址空间的增长方向
①首先我们要打印的一个区域的代码区:
现在要打代码的地址,可是我们要以谁做为我们对应的代码区呢?
在我们整个的代码当中,我们就有一个叫做main函数的函数,其中函数名代表的就是它的地址。
我们用main函数充当我们代码区的地址,所以代码区的地址我们就有了:
②字符常量序区,那么需要有个字符常量:
那么告诉我%p这里我们在输出的时候,那么是需要输出的是str呢?还是&str呢?还是*str呢?
那么很显然,我们要打的是这个字符串常量,它的起始地址在str变量里面。字符指指针变量也是变量,它里面保存的就是这个字符串的起始地址,所以打印str就行了
③我们要打印已初始化全局变量和未初始化变量:
在main函数外定义两个全局变量,如图:
打印:
④我们要打印堆区:
请问这次在打印时打印的是men还是&men呢?
答案是:men,因为要打印的是堆它对应的地址;
⑤打印栈的地址:
那么我们栈区的变量在哪呢?
我们在函数当中定义的变量叫做局部或者临时变量,调用函数时形成该变量,函数返回时该变量被释放。
那么为什么呢?
因为调用函数时,我们需要在栈上为该函数申请,我们对应的栈空间的。
那么同样的,main函数也是函数。所以之前定义的str,men都是局部变量,局部变量在我们对应的栈上。
所以我们这里取地址是这样。
所以整个代码:
运行打印:
我们可以看到它就在这里依次向上增长
脑子里只要有这张图。
我们就知道 c语言当中全局变量,局部变量还有很多变量,那么它为什么那么最终临时变量就临时性呢?全局变量为什么一直有效?原因我们就能清楚了。
其中我们要知道栈区,它是向地址减少方向增长,向下增长。
而我们的堆区,它是向地址增大方向增长,也就是堆栈相对而生。
验证栈,堆地址的增长方向:
验证栈的增长方向:
打印结果:
那么为什么是向地址减少的方向增长呢?
因为栈向地址减小方向增长,先定义的变量,先入栈,后定义变量后入栈,所以它的地址当然会小。
验证堆空间:
打印结果:
你会发现堆和栈它两个的地址差别很大,它两个之间有一大段的镂空。那么这段镂空是什么?我们后面讲动静态库的时候再说。反正呢,那么堆栈是相对而生的。我们这么理解就OK了来。
验证关于static的语法问题
我们知道全局变量它会一直存在,并不随着一个函数的调用和返回,这个全局变量不会释放。那么这就说明,不论是你初始化还是未初始化,只要是全局变量,这个区域我们统称为全局数据区。
在学c语言的时候,我们有一种变量叫做static,那么把我们对应的一个变量用static这个来进行修饰。
static并不会随着这个函数的使用完毕而释放,它只做一次初始化,首次调制函数是初始化。往后它就直接使用这个变量。这个函数它的生命周期就不随着函数的调用和释放,或者是返回这个变量就不会释放了。
问题是,为什么我们用static这个变量一修饰这个a,那么它就不会被释放了呢?
打印结果:
对比全局变量:
说明我们对应的static修饰的叫做局部变量,编译的时候已经被编译到全局数据去了,所以它才不会随着你函数的调用,然后去自动释放的,因为它已经是一种全局变量了。
只不过它是那么身在曹营,身不由己。
static在一个函数代码块里,所以它只能在这个代码块里面被使用,这叫做这个变量,作用域只能在函数里面,但是它的生命周期已经是全局了。