C内存结构分析
C内存结构分析 基础知识 个由C/C编译的程序占用的内存分为以下几个部分 1、栈区(stack )-由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作 方式类似于数据结构中的栈。 2、堆区(heap ) 一 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回 收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。 3、全局区(静态区)(static )-,全局变量和静态变量的存储是放在一块的,初始化的全局 变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区 域。_程序结束后有系统释放 4、文字常量区一常量字符串就是放在这里的。程序结束后由系统释放 5、程序代码区一存放函数体的二进制代码。 程序代码区 C程序的代码和数据是分开存放的,函 数的代码都存储于代码区中。 堆区 栈区 通常,全局变量,静态局部变量以及文字 常量都存储于这块区域中。 例子程序 //main.cpp includeiostream.h includestring.h //includemalloc.h //malloc 的头文件可以为includemalloc.h也可以为 includestdlib.h includestdlib.h int a 0;全局初始化区 char *pl;全局未初始化区 main { const char* m 123456; 〃指向常量的指针 int b;栈 char s[] abc;栈 char *p2;栈 char *p3 123456; 123456在常量区,p3 在栈上。 static int c 0 ;全局静态初始化区 pl char *malloc10; p2 char *malloc20; 分配得来得10和20字节的区域就在堆区。 strcpypl, 123456; 123456放在常量区,编译器可能会将它与p3所指向的 ”123456”优化成一个地方。 coutm p3l0endl;〃 结果为 1 coutpl p3l0endl;〃结果为 0 coutpl p3 endl;〃结果为 123456 123456 ■ 函数在栈上创建在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结 束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,一般使用寄存 器来存取,效率很高,但是分配的内存容量有限。 ■ 堆上创建从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任 意多少的内存,程序员自己负责在何时用free或delete来释放内存。动态内存的生存期由 程序员自己决定,使用非常灵活。 ■ 全易倔区从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程 序的整个运行期间都存在。例如全局变量,static变量。 对于这个,我们可以看个例子 avoid test { static int const_a 23; int comm_a 44; std cout const_啲地址是 const_a std endl; Stdcout Lomd地址是“ comm_a stdendl; mint _tmainint argc, _TCHAR* argv[] test ; int* ptr int*0X0041B008; std cout ptr指针中保存的值是 *ptr std endl; int* ptr2 int*0 x0012FE3C; std cout ptr2旨针中彳呆存的值是 *ptr2 std endl; 析在这里我们主要讨论静态变量(在函数内定义)与普通变量这间的生命同期,在test 函数中,我们定义了一个静态变量const_a,假设保存在编号为0041b008地址块中,同时 定义了一个普通变量Comm_a,假设其保存地址是0012FE3C。在main函数中,我们执行 test函数,执行完后,我们直接从上面两个地址块去取数据,我们可以看到静态变量所在 的地址块的值一直存在,因为它的值是分配在了全局代码区,而普通变量所在的块,因为函 数已经执行完毕,分配在栈上的空间被回收,并重新赋了一个随机值,我们再也取不出里 面原有的数据了。 还有,大家可以查看反汇编代码,会发现全局变量编译时就已经分配好内存了,只是 在我们用时将这块地址礎合我们的变量指针而已 - 23i rib崂旳fceei 反编代码为 训二 fcwi M4IH1E4Wttl 〃通过编译量在取值 ■ 常量区文字常量分配在文字常量区,程序结束后由系统释放。 关键要注意的是,它的生命周期是到程序结束后才释放,而不是函数结束完就释放 了。 ■ 代码区存放整个程序的代码,因为存储是数据和代码分开存储的。 文字常量区与栈区解析 我们现来看一下文字常量的定义 常量之所以称为文字常量,其中文字是指我们只能以它的值的形式指代它,常量 是指它的值是不可变的。同时注意一点文字常量是不可寻址的(即我们的程序中不 可能出现获取所谓常量20的存储地址20这样的表达式),虽然常量也是存储在内存 的某个地方,但是我们没有办法访问常量的地址的。 常量是有类型的 1.字符型char 卜个字节表示,通常表示单个字符或小整数,字符型常量用一对单 引号,夹着一个字符表示。 ■ 1)可打印字符常量表示a 2、,字符常量在内存中的存储格式依赖于ASCH码表的。 ■ 2)不可打印字符常量,通过斜杠、\表示 、\n换行符、\\反斜杠、\t水平制表符0空(NULL)字符 2 整型int | 个机器字长度的整数值。短整型short半个机器字长度的整数 值。长整型long .个或两个机器字长度的整数值。在32位机器中,int和 long通常相同。 ■上面提到的char字符型,也可看作长度为一个字节的字符型整数。 通过下面这个小例子,可以看到char型数据,不同初始化方法,内存格式也是不同 的。charal; coutalendl; 〃输岀结果为50 ,参照ASC表,字符常量T 在内存中是十进制数49。 char bl; coutblendl;〃输岀结果为2,实际 上,字符常量还可以初始化int、long等类型数据, intcl;coutclendl;//输岀结果也是 50, 而 char azr;coutaendl;//输岀结果为 1 intal;couta