从一个微型例子看“C/C++的内存分配机制”和“数组变量名与指针变量名”(转)
C++的内存有五大分区:堆区、栈区、自由存储区、全局/静态存储区、常量存储区。
五个数据段:数据段、代码段、BSS段、堆、栈
内存分配方式有三种:
- 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
- 在栈上创建。 在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 这个大小在linux上可以使用:ulimit -a | grep stack 来查看
- 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
#include <iostream>
using namespace std;
char * GetMemory(void){
//p_arr是个数组的起始地址,这个数组的内容是存放在栈上面的。另外,非常值得一
//提的是:系统没有为p_arr单独分配一个指针变量用来存放数组p_arr的起始地址。
char p_arr[] = "p_arr : hello world"; //p_heap是一个指针变量,这个指针变量存在于栈上面,指针变量的值是指向的由
//malloc分配得到的堆上的内存空间的起始地址。
char *p_heap=(char *)malloc(sizeof(char)*20); //ptr是一个指针变量,这个指针变量存在于栈上面,指针变量的值是指向的后面字符
//串的起始地址,这个字符串是常量,是存在于静态存储区域的,不是在栈上,也不是
//在堆上。
char *ptr = "ptr : hello world"; strcpy(p_heap,"p_heap: hello world");
printf("%08X\n",p_arr);
printf("%08X\n",&p_arr);
printf("%08X\n",p_heap);
printf("%08X\n",&p_heap);
printf("%08X\n",ptr);
printf("%08X\n",&ptr);
puts(p_arr);
puts(ptr);
puts(p_heap);
//return p_arr;
return ptr;
}
int main(){
char * str=NULL;
str = GetMemory();
printf("%08X\n",str);
printf("%08X\n",&str);
puts(str);
return 0;
}
上面程序输出的结果是:
这里面8有8行关于地址的输出,分别描述如下:
- DC726BF0这个地址是栈上面的,函数退出后,这块地址空间就废弃了。
- DC726BF0是栈上面的地址,之所以和上面一样,是因为栈上并没有分配一个单元用来存放数组指针,这个是使用char []和char * 的最根本的区别。
- 0EB29010这个地址是在堆上面的,直到delete才会释放掉这块内存。
- DC726BE8是栈上面的地址,用来存放指针变量p_heap的单元,p_heap的值就是上面堆上内存的地址。
- 004009D8这个地址是静态存储区的,函数退出后不会清除掉
- DC726BE0栈上面的地址,用来存放指针变量ptr的单元,ptr的值就是上面静态的存储区地址
- 004009D8这个是由函数返回的地址,就是上面静态存储区的地址
- DC726C28这个地址是main函数局部变量的存放地址,位置要比栈上的位置低
栈-->main函数局部变量地址-->堆-->静态变量地址
可以看出来,静态地址最低,然后依次是:堆、main、栈。
另外的,还有一个“先声明的变量时在高地址区还是在低地址区”的问题,这个问题要看栈怎么生长的了,如果栈底在高内存,向低地址生长,自然先声明的变量在高地址。例如:在linux中,栈底就是在高地址的,所以后面声明的变量地址就是低地址。此外,在堆上的地址一般是从低到高的。下面的例子可以清晰的看出这两种情况。
#include <iostream>
class c1
{
public:
int number;
};
main()
{
int a =3;
int b =4;
printf("addr of a on stack: 0x%X\n",&a);
printf("addr of b on stack: 0x%X\n",&b);
c1 * c=new c1();
c1 * d=new c1();
int * e =new int(100);
printf("addr of c on stack: 0x%X--0x%X(on heap)\n",&c,c);
printf("addr of d on stack: 0x%X--0x%X(on heap)\n",&d,d);
}
以上代码的输出:
对于上面的输出解释如下:
- a,b是位于main函数栈上的变量,他们地址的增长方向是从高到低的。另外,也请注意a和b的地址相差的距离是4个字节(虽然是64位机器和OS,但是int占用的空间还是32位)
- c,d是位于main函数栈上的指针变量,同样是从高到低增长。这次要注意,他们相差的距离是8个字节(因为是c和d都是指针变量,要能够存下64位地址长度的数据)
- 最后,要注意c和d指向的结构都位于堆上,这次他们地址的增长方向就是从低到高(从0xE7F1010到0xE7F1030)了。
转载地址:http://www.cnblogs.com/welkinwalker/archive/2011/01/05/1926203.html
从一个微型例子看“C/C++的内存分配机制”和“数组变量名与指针变量名”(转)的更多相关文章
- C语言定义一个指针变量
10.2.1 定义一个指针变量 对指针变量的定义包括三个内容: (1) 指针类型说明,即定义变量为一个指针变量: (2) 指针变量名: (3) 变量值(指针)所指向的变量的数据类型. 其一般形式为: ...
- Spark小课堂Week7 从Spark中一个例子看面向对象设计
Spark小课堂Week7 从Spark中一个例子看面向对象设计 今天我们讨论了个问题,来设计一个Spark中的常用功能. 功能描述:数据源是一切处理的源头,这次要实现下加载数据源的方法load() ...
- 一个例子看懂所有nodejs的官方网络demo
今天看群里有人用AI技术写了个五子棋,正好用的socket.io,本身我自己很久没看nodejs了,再加上Tcp/IP的知识一直很弱,我就去官网看了下net.socket 发现之前以为懂的一个官方例子 ...
- SQL Server Reporting Service(SSRS) 第一篇 我的第一个SSRS例子
很早就知道SQL SERVER自带的报表工具SSRS,但一直没有用过,最近终于需要在工作中一展身手了,于是我特地按照自己的理解做了以下总结: 1. 安装软件结构 SSRS全称SQL Server Re ...
- 一个简单例子:贫血模型or领域模型
转:一个简单例子:贫血模型or领域模型 贫血模型 我们首先用贫血模型来实现.所谓贫血模型就是模型对象之间存在完整的关联(可能存在多余的关联),但是对象除了get和set方外外几乎就没有其它的方法,整个 ...
- 一个经典例子让你彻彻底底理解java回调机制
转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273),请尊重他人的辛勤劳动成果,谢谢 所谓回调: ...
- 回调--一个经典例子让你彻彻底底理解java回调机制
本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273),请尊重他人的辛勤劳动成果,谢谢 以前不理解什么叫回调 ...
- Lea指令计算地址(用于四则混合运算),附上一个函数调用例子及其反汇编代码,很清楚
比如你用local在栈上定义了一个局部变量LocalVar,你知道实际的指令是什么么?一般都差不多像下面的样子: push ebp mov esp, ebp sub ...
- 用 Lua 实现一个微型虚拟机-基本篇
用 Lua 实现一个微型虚拟机-基本篇 目录 介绍 机器指令模拟 最终核心代码 虚拟机内部状态可视化 完整项目代码 后续计划 参考 介绍 在网上看到一篇文章 使用 C 语言实现一个虚拟机, 这里是他的 ...
随机推荐
- Gradle 1.12用户指南翻译——第二十一章. Gradle 插件
昨天晚上只顾着和女朋友看<匆匆那年>电视剧的最后几集,所以说好的Android文档<Gradle 插件用户指南>第五章自然也没翻译多少.所以今天也发不了第五章的翻译了,就发几个 ...
- python +Django 搭建web开发环境初步,显示当前时间
1.python 的安装 网上很多关于django跟python 开发的资料,这块我正在实习准备用这个两个合起来搞一个基于web 的东西出来现在开始学习,写点东西记录一下心得. 开发环境是window ...
- 【Android 应用开发】AndroidUI设计 之 图片浏览器
图片浏览器效果图 : 源码下载地址 : -- CSDN : http://download.csdn.net/detail/han1202012/6875083 -- GitHub : https:/ ...
- 对FMDB的封装JRDB
在自己开发中,每次用到数据库都会纠结是使用CoreData还是FMDB.CoreData虽然Api简单,但是调用栈非常复杂,要初始化一个Context需要至少20行代码.显然,对于这种这么恶心的情况, ...
- 【Visual C++】游戏编程学习笔记之一:五毛钱特效之透明和半透明处理
本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44163799 作者:ZeeCod ...
- C#中任意类型数据转成JSON格式
/// <summary> /// List转成json /// </summary> /// <typeparam name="T&quo ...
- 【Qt编程】基于Qt的词典开发系列<十二>调用讲述人
我们知道,win7系统自带有讲述人,即可以机器读出当前内容,具体可以将电脑锁定,然后点击左下角的按钮即可.之前在用Matlab写扫雷游戏的时候,也曾经调用过讲述人来进行游戏的语音提示.具体的Matla ...
- Linux管线命令 - cut,grep,sort,uniq,wc,tee,tr,col,join,paste,expand,split,xargs
在每个管线后面接的第一个数据必定是『命令』喔!而且这个命令必须要能够接受 standard input 的数据才行,这样的命令才可以是为『管线命令』,例如 less, more, head, tail ...
- LeetCode(46)-Remove Nth Node From End of List
题目: Given a linked list, remove the nth node from the end of list and return its head. For example, ...
- Android性能优化之UI渲染性能优化
版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 本篇博客主要记录一些工作中常用的UI渲染性能优化及调试方法,理解这些方法对于我们编写高质量代码也是有一些帮助的,主要内容包括介绍CPU,GPU的职 ...