由一个小程序看内存分配

本文通过实例代码解析编译器和Windows环境下内存分配的方式,从栈、堆到全局变量的存储顺序,阐述内存管理的原理。

很多朋友对编译器和系统对变量如何分配内存不是很清楚,也很容易搞糊涂,我们下面 就以一个小程序为例看看编译器和系统是如何为变量分配内存的.

注意:我的编译环境为VC++6.0. 系统平台为: windows XP 不同的编译环境和操作系统可能有所不同.

#include < iostream>

using namespace std;

int main()
{
    int a[5] = { 1,2,3,4,5} ;
    int b[5] = { 6,7,8,9,10} ;
    cout << b[6] << endl;
    return 0;
}
输出结果 2
很多朋友可能对这个结果很是迷惑,会以为b[6]属于越界访问,为什么不但没 有报错,反而输出了结果呢?为了解决这个问题,我们把这10个数字在内存中的存储情况列出来:
                                                 

 

0012FF7C

5

0012FF78

4

0012FF74

3

0012FF70

2

0012FF6C

1

0012FF68

10

0012FF64

9

0012FF60

8

0012FF5C

7

0012FF58

6

   a[4]

   a[3]

   a[2]

   a[1]

  ß a[0]

   b[4]

   b[3]

   b[2]

   b[1]

  ß b[0]

 

根据上面的图表我们可以看出:数据在内存中的 存储情况。即编译器和系统在为变量分配是从高地址开始分配的.

分析代码:


 int a[5] = { 1,2,3,4,5} ;

我们定义了一个数组a,那么此时系统和编译器便从栈地址区找出一块空闲内存分配给数组a.然后数组a便在这块内存中 从高地址开始存储,即a[4]--->a[0]

   int b[5] = { 6,7,8,9,10} ;

我们又定义了一个数组b,那么系统和编译器以同样的方法对待b,不过这次是接着a的结束地址往下开始分配(由高往 低).

最后的结果便是上面的图表所列的情况,从上面表中我们可以看出b[5]便是a[0]单元,b[6]是a[1]单元.

所以输出结果便是2了.

也许有些朋友对这个在理解上有些困难,我们再来看一个简单的:

#include < iostream>

using namespace std;

int main()

{

    int a = 2;

    int b = 3;

    int * p = & b;

    cout << * p << endl;

    cout << * (++ p) << endl;

    return 0;

}

输出结果:

3

2

我们可以使用:

 cout << &a << endl;

 cout << &b << endl;

来查看a,b在内存中的地址情况:

0012FF7C

0012FF78

可以看出a的地址高于b的地址.且他们之间差了4个字节,这是因为a占4个字节.

这样我们应该就可以理解为什么输出结果为3 2了。p开始指向变量b,即在变量p的内存空间中存有b的地址。我们输出*p,即输出b的值为3.而后我们输出*(++p)即现对p里面的内容+1,然后 输出*p.

这里有一点提醒的是: +1操作并不是总是+1,它有它自己的单位,在这里它的单位为4个字节,即一个int型的大小.所以在p+1后就指向了变量a.所以输出结果就为2了.

 

好的,问题解决了,但是新的问题又来 了。

那么全局变量,以及函数中的参数也是 如此吗?

Code:
    • #include <iostream>   
    • using   namespace  std;   
    • int  x;   
    • int  y;   
    • void  function( int  x, int  y)   
    • {   
    •     y = 1;   
    •     x = 2;   
    •      int  kk;   
    •      int  yy;   
    •     printf( "x = %d,y = %d/n" ,x,y);   
    • }   
    • int  main()   
    • {   
    •     x = 1;   
    •     y = 2;   
    •     function(x,y);   
    •      int  z;   
    •      int  t;   
    •     printf( "x = %d,y = %d/n" ,x,y);   
    • }  

我们可以对上面的一段代码加上断点,对其进行调试然后查看各个变量的地址进行比较就可以看出。全局变量和函数参数在 内存中的存储是由低地值到高地址的.这又是什么原因呢?

我们需要清楚的是:内存分为不同的区域用于不同的作用.

全局变量是放在全局区里的。函数的参数是放在堆区中的.对于这点可能有些朋友会不明白了,函数参数为什么会放到堆区 呢?这是因为我们的函数是在程序运行中进行动态的调用的.在函数的编译阶段根本无法确定他会调用几次,会需要多少内存.即使可以确定那时候就为变量分配好 内存着实也是一种浪费。所以编译器为函数参数选择动态的分配..即在每次调用函数时才为它动态的进行分配空间.

而那为什么这两个区域的变量在内存中的存储就是顺序的呢?

我想这个问题就是栈机制的影响吧.函数内部定义的非动态分配的,非静态变量都是放在栈区的.我们大家都清楚栈有着后 进先出的特性.并且栈区不但要保存部分变量,还有保存函数的入口地址,断点地址,参数等.这种栈的机制对函数调用,中断都有着很重要的作用.

而在全局区,堆区中没有这种机制,也无需这种机制,也就顺序分配了.

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值