C++中不同变量、函数在内存中的内存情况《转》
一、一个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个字节还不清楚是不是编译器原因。
常量的开始地址来看跟全局变量应该属于一个区。堆区的地址开头也是另外一个段。
补充一点:数组变量内部元素是按照元素下标从低地址到高地址压栈的。
一般局部变量一般是从高低地址到低地址压栈的。
从上面结果来看全局变量实际可能在堆区。
以上内容主要参考http://blog.csdn.net/benny5609/article/details/2217258原创文章
C++中不同变量、函数在内存中的内存情况《转》的更多相关文章
- 借助JavaScript中的时间函数改变Html中Table边框的颜色
借助JavaScript中的时间函数改变Html中Table边框的颜色 <html> <head> <meta http-equiv="Content-Type ...
- python3中的 zip()函数 和python2中的 zip()函数 的区别
python3中的 zip()函数 和python2中的 zip()函数 的区别: 描述: zip() 函数用于将可迭代对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象. ...
- python2中的unicode()函数在python3中会报错:
python2中的unicode()函数在python3中会报错:NameError: name 'unicode' is not defined There is no such name in P ...
- C中的qsort函数和C++中的sort函数的理解与使用
一.qsort()函数 原型:_CRTIMP void __cdecl qsort (void*, size_t, size_t,int (*)(const void*, const void*)); ...
- javascript中判断变量时变量值为 0 的特殊情况
有时候我们在js中会直接判断变量是否存在值,下面列举一些情况: var a = 0; var b = 1; var c = ' '; var d; console.log( a ? 1 : null) ...
- Matlab中的eig函数和Opecv中eigen()函数的区别
奇异值分解的理论参见下面的链接 http://www.cnblogs.com/pinard/p/6251584.html https://blog.csdn.net/shenziheng1/artic ...
- C语言中所有变量和常量所使用的内存总结
(1)相同点:三种获取内存的方法,都可以给程序提供可用内存,都可以用来定义变量给程序用.(2)不同点:栈内存对应C中的普通局部变量(别的变量还用不了栈,而且栈是自动的,由编译器和运行时环境共同来提供服 ...
- 教你一招:Excel中使用MID函数获取身份证中的出生年月日
MID字符串函数,作用是从一个字符串中截取出指定数量的字符 MID(text, start_num, num_chars) text被截取的字符 start_num从左起第几位开始截取(用数字表达 ...
- DllImport dll中有些啥函数 及 dll中是否用到了别的dll
在加载dll的时候不知道dll中有哪些接口怎么办,或者使用别人封装的东西时报出类似于“无法在 DLL“XXX.dll”中找到名为“XXX函数”的入口点.” 1.通过LordPE这个软件来看dl ...
- body中的onload()函数和jQuery中的document.ready()有什么区别?
1.我们可以在页面中使用多个document.ready(),但只能使用一次onload(). 2.document.ready()函数在页面DOM元素加载完以后就会被调用,而onload()函数则要 ...
随机推荐
- ubuntu 双网卡建网桥脚本实现
#!/bin/bash interface1=`ls /sys/class/net|grep en|awk 'NR==1{print}'` interface2=`ls /sys/class/net| ...
- python学习:字典排序
按字典值排序 按照字典value排序,类似sort -k 命令 import operator x= {1:2,3:4,4:3,2:1,0:0} sorted_x = sorted(x.ite ...
- SqlBulkCopy 参数配置示例
SqlBulkCopy 做为SQL Server 官方 批量入库类,性能不会太差.针对其参数做了一些测试. A. 先准备测试场景 ,关于SqlBulkCopyOptions.KeepIdenti ...
- MYSQL索引的类型和索引的方式
索引的类型: normal:表示普通索引 unique:表示唯一的,不允许重复的索引,如果该字段信息保证不会重复例如身份证号用作索引时,可设置为unique full textl: 表示 全文搜索的索 ...
- java学习笔记(详细)
java平台 1.J2SE java开发平台标准版 2.J2EE java开发平台企业版 java程序需要在虚拟机上才可以运行,换言之只要有虚拟机的系统都可以运行java程序.不同系统上要安装对应的虚 ...
- Qt 开发 MS VC 控件终极篇
Qt 开发 MS VC 控件终极篇 1. 使用 MSVC2015 通过项目向导创建 Qt ActiveQt Server 解决方案 项目配置:以下文件需要修改 1. 项目属性页->项目属性-&g ...
- # C# 如何调用动态连接库?
导入命名空间 using System.Runtime.InteropServices; 把 非托管DLL放入执行程序同级目录,比如 Debug .Release . [DllImport(" ...
- javascript高级程序设计第三章的一些笔记
[TOC] 1. 语法 1.1 区分大小写 变量.函数名和操作费都区分大小写. 1.2 标识符 标识符指变量.函数.属性的名字,或者函数的参数.标识符按以下规则组合: 第一个字符必须是一个字母,下划线 ...
- foo的出现
在计算机程序设计与计算机技术的相关文档中,术语foobar是一个常见的无名氏化名,常被作为“伪变量”使用. 从技术上讲,“foobar”很可能在1960年代至1970年代初通过迪吉多的系统手册传播开来 ...
- 网络基础Cisco路由交换二
三层交换技术 作用: 使用三层交换技术实现VLAN间通信. 三层交换=二层交换+三层转发 基于CEF的快速转发 主要包含两个转发用的信息表: 转发信息库(FIB):FIB类似于路由表,包含路由表中转发 ...