原创 由一个小程序看内存分配

2010-1-22 13:37 2774 5 5 分类: MCU/ 嵌入式

http://student.csdn.net/space.php?uid=43658&do=thread&id=5413


由一个小程序看内存分配 王富涛 2009-12-15 1338
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


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


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


#include <iostream>


using namespace std;


int main()


{


    int a[5] = {12345};


    int b[5] = {678910};


    cout << b[6] << endl;


    return 0;


}


输出结果 2


很多朋友可能对这个结果很是迷惑,会以为b[6]属于越界访问,为什么不但没有报错,反而输出了结果呢?为了解决这个问题,我们把这10个数字在内存中的存储情况列出来:                                                 



0012FF<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />7C


5


a[4]


0012FF78


4


a[3]


0012FF74


3


a[2]


0012FF70


2


a[1]


0012FF6C


1


? a[0]


0012FF68


10


b[4]


0012FF64


9


b[3]


0012FF60


8


b[2]


0012FF5C


7


b[1]


0012FF58


6


?b[0]


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


分析代码:


int a[5] = {12345};


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


int b[5] = {678910};


我们又定义了一个数组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;


来查看ab在内存中的地址情况:


0012FF7C


0012FF78


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


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


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


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


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


Code



1.                               #include <iostream>   


2.                               using namespace std;   


3.                               int x;   


4.                               int y;   


5.                               void function(int xint y)   


6.                               {   


7.                                   y = 1;   


8.                                   x = 2;   


9.                                   int kk;   


10.                               int yy;   


11.                               printf("x = %dy = %d\n"xy);   


12.                           }   


13.                           int main()   


14.                           {   


15.                               x = 1;   


16.                               y = 2;   


17.                               function(xy);   


18.                               int z;   


19.                               int t;   


20.                               printf("x = %dy = %d\n"xy);   


21.                           }  


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


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


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


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


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


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


仅作一个参考。更深的问题大家一起讨论哈。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
5
关闭 站长推荐上一条 /3 下一条