更多课程 选择中心

C/C++培训
达内IT学院

400-996-5531

C++开发中不同变量、函数在内存中的内存情况

  • 发布:C++培训
  • 来源:学习笔记
  • 时间:2017-09-08 09:51

一、一个C++编译的程序占用的内存分为以下几个部分

1、栈区:由编译器自动分配 存放函数的参数值,局部变量的值等,操作方式类似于数据结构中的栈。

2、堆区:一般由程序员分配释放,若程序员不释放,程序结束时 可能 有系统收回。它与数据结构中的堆是两回事。分配方式类似于链表。

3、全局区(静态区):全局变量和静态变量是存储放在一块的,初始化的全局变量和静态变量在一个区域,未初始化的在相邻的另一个区域。

程序结束后由系统释放。

4、文字常量区:常量字符串就存放在这里。程序结束后有系统自动释放。

5、程序代码区:存放函数体的二进制代码。

二、堆栈的理论知识

1、申请方式

栈:有系统自动分配。例如定义局部变量int i = 0;函数传参时使用值传递。

堆:需要程序员自己申请并指明大小。如用malloc函数和new运算符。

2、申请后的系统响应

栈:只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,负责报告栈溢出异常。

堆:这个设计到系统的内存管理,操作系统有一个记录空闲内存地址的链表,然后根据系统的内存分配策略分配内存。

3、申请大小的限制

栈:在windows下,栈是向低地址扩展的数据结构,是一块连续的内存区域。也就是说栈底和栈顶的地址和最大容量是

系统预先规定好的。在windows下据说是栈大小是2M,如果申请的空间超过栈的剩余空间时将提示溢出。因此栈的

空间较小。

堆:堆是向高地址扩展的数据结构,是不连续的内存区。因为系统用链表来存储空闲内存的地址的,而链表遍历的方向

是从低地址到高地址。堆的大小受限于计算机系统中有效地虚拟内存。获得的空间比较灵活也比较大。

4、效率方面

堆:速度比较慢,容易产生碎片,不过用起来方便。在windows最快的是利用VirtualAlloc分配内存,他不在堆也不在栈中,

而是直接在栈的地址空间中保留一块内存。使用起来速度快,灵活。

栈:速度快,不过由系统自动分配和控制。

5、存放内容方面

堆:一般是在堆的头部用一个字节放堆的大小。堆中具体内容有程序员安排。

栈:在函数调用时第一个进栈的是主函数中下一条指令(函数执行语句的下一条可执行语句)地址,然后是各个函数的参数,

大多数C/C++编译器中,函数参数是从右往左入栈,然后是函数中的局部变量。注意:静态变量不如栈的。本次函数调

用结束后,局部变量先出栈,然后是函数参数,最后栈顶指针指向最开始存的主函数中下一条指令地址,程序由该点继

续运行。

三、实例解说

//全局初始化区

int i1 = 0;

int i2 = 0;

int i3 = 0;

//全局初始化区

static int i4 = 0;

static int i5 = 0;

static int i6 = 0;

//全局未初始化区

int i7;

int i8;

int i9;

void Creat()

{

cout<<"Creat"<<endl;

}

void Add()

{

cout<<"Add"<<endl;

}

void Delete()

{

cout<<"Delete"<<endl;

}

int Max(int a,int b)//在调用此函数时参数从右往左开始压栈

{

return a>b?a:b;

}

int _tmain(int argc, _TCHAR* argv[])

{

cout<<"打印全局初始化区变量i1-i3的地址:"<<endl;

cout<<&i1<<" "<<&i2<<" "<<&i3<<endl;

cout<<"打印全局初始化区静态变量i4-i6的地址:"<<endl;

cout<<&i4<<" "<<&i5<<" "<<&i6<<endl;

cout<<"打印全局未初始化区变量i7-i9的地址:"<<endl;

cout<<&i7<<" "<<&i8<<" "<<&i9<<endl;

cout<<"依次打印上面三个函数Creat、Add、Delete地址:"<<endl;

cout<<&Creat<<endl;

cout<<&Add<<endl;

cout<<&Delete<<endl;

//栈区

int c1 = 'a';

int c2 = 'b';

int c3;

int c4;

cout<<"打印主函数内局部变量c1-c4地址,其中c3,c4未初始化"<<endl;

cout<<&c1<<" "<<&c2<<" "<<&c3<<" "<<&c4<<" "<<endl;

char *pStr1 = "12345";//12345在常量区,pStr在栈上

char *pStr2 = "1122";

void *p = pStr1;

void *q = pStr2;

cout<<"打印常量地址"<<endl;

cout<<p<<endl;

cout<<q<<endl;

static int i10 = 0;//全局(静态)初始化区

cout<<"在局部函数中定义静态变量地址,请于上面答应的其他全局区地址作比较"<<endl;

cout<<&i10<<endl;

int *p1 = new int;//堆区

int *p2 = new int;//堆区

cout<<"打印堆区地址"<<endl;

cout<<p1<<endl;

cout<<p2<<endl;

strcpy(pStr1,"1144");//12345在常量区,编译器可能将pStr1文字常量1144优化成一个地方

getchar();

return 0;

}

输出:

以上结果在VS2008中测试。对上面结果地址观察发现,全局未初始化区的变量是按从高到低地址按申明定义的

顺序压栈,变量i7紧邻全局初始化段的第一个变量i1.而全局初始化段的变量(包括静态,不做区分的)从低地址

到高地址按申明的顺序压栈(不是指上面所指的栈区,请区别开来,这是就地址变化过程而言的,你会看到它与

局部函数变量起始地址完全不同)。函数在程序代码段中地址是按申明顺序递增的。函数局部变量在栈去是按照

申明顺序从高到低的地址进栈的。这里看到我定义的几个int变量地址相差是12个字节还不清楚是不是编译器原因。

常量的开始地址来看跟全局变量应该属于一个区。堆区的地址开头也是另外一个段。

补充一点:数组变量内部元素是按照元素下标从低地址到高地址压栈的。

一般局部变量一般是从高低地址到低地址压栈的。

从上面结果来看全局变量实际可能在堆区。

预约申请免费试听课

填写下面表单即可预约申请免费试听!怕钱不够?可就业挣钱后再付学费! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!

上一篇:什么是C语言,C语言优缺点和用途及发展历史
下一篇:C语言90道试题,C语言入门进阶试题资料

C语言创建windows窗口实例

C++回调函数是什么?

C++ shared_ptr和动态数组

C语言有哪些关键词,C语言44个关键词大全

Copyright © 2023 Tedu.cn All Rights Reserved 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有

选择城市和中心
黑龙江省

吉林省

河北省

湖南省

贵州省

云南省

广西省

海南省