堆和栈的一些知识
堆(heap)在空间上手动分配或释放,通过C语言中的malloc,C++中的new来完成,分配的空间可以不连续,是一种链式结构;堆有很大的存储空间;
栈(stack)在空间上由操作系统分配或回收;栈的空间有限;程序在编译期间完成对函数和变量在栈上的分配,在运行时对函数的调用传递参数的传递是在栈上完成,且分配一般是连续的,是一种线性结构。
下面通过一段程序,可以看出堆和栈的一些区别:
#include <stdio.h>
#include <stdlib.h>
int x; //全局变量,放在静态数据区,连续存放
int y;
int z;
int fn(int u,int v,int w/*参数变量及函数返回值放在栈stack,连续*/)
{
int a; //函数内部变量放在动态数据区(栈stack)上,连续
int b;
int c;
static int l;
static int m; //静态全局变量,放在静态数据区,不一定连续
static int n;
char *p = (char *)malloc(4); //分配空间,放在动态数据区(堆heap)上,不连续
char *q = (char *)malloc(4);
char *s = (char *)malloc(4);
printf("参数变量放在动态数据区(栈stack):/n");
printf("&u=%08x/n",&u);
printf("&v=%08x/n",&v);
printf("&w=%08x/n",&w);
printf("/n/n全局变量放在静态数据区:/n");
printf("&x=%08x/n",&x);
printf("&y=%08x/n",&y);
printf("&z=%08x/n",&z);
printf("/n/n静态全局变量放在静态数据区:/n");
printf("&l=%08x/n",&l);
printf("&m=%08x/n",&m);
printf("&n=%08x/n",&n);
printf("/n/n函数内部变量放在动态数据区(栈stack):/n");
printf("&a=%08x/n",&a);
printf("&b=%08x/n",&b);
printf("&c=%08x/n",&c);
printf("/n/n分配空间放在动态数据区(堆heap):/n");
printf("p=%08x/n",p);
printf("q=%08x/n",q);
printf("s=%08x/n",s);
return 1;
}
void main()
{
fn(1,2,3);
}
执行结果如下图。
参数变量放在动态数据区(栈stack):
&u=0013ff28
&v=0013ff2c
&w=0013ff30
全局变量放在静态数据区:
&x=00427c40
&y=00427c44
&z=00427c48
静态全局变量放在静态数据区:
&l=00427c50
&m=00427c3c
&n=00427c4c
函数内部变量放在动态数据区(栈stack):
&a=0013ff1c
&b=0013ff18
&c=0013ff14
分配空间放在动态数据区(堆heap):
p=00033940
q=00033978
s=000339b0
一个进程的内存空间逻辑分为:代码区、静态数据区及动态数据区。堆栈就放在动态数据区。进程的每个线程均有自己的“栈”,均为本地内部变量互不影响(可以想想同名的全局变量和函数内部变量,是能正确访问的)。
程序执行至:fn(1,2,3)处时的栈顶指针ESP = 0012FF34,进入fn()内部后,栈顶指针ESP = 0012FF24,两者相差16个字节,分别为传递的三个参数和保存的一个函数返回:
ESP = 0012FF30 ------------> 3 //参数从右向左依次压栈
ESP = 0012FF2C ------------>2
ESP = 0012FF28 ------------> 1
ESP = 0012FF24 ------------> ret //函数返回值
待fn()函数调用完毕后,栈顶指针ESP = 0012FF28,与进入时的ESP = 0012FF34不等,原因是VC默认通用函数时规则为“__cdecl”(fn()函数不清理堆栈,由被调函数main()去清理,若fn()函数前使用关键字“__stdcall”时,进出函数时的栈顶指针ESP就一致了)。