程序中的三国天下是介绍:
栈, 堆, 静态存储区
栈区
主要保存函数调用时所需要的参数信息.局部变量等信息,还包括一些看不到的返回地址,寄存器信息等等(可以说没有栈程序就没法运行)。栈就是一种行为,后进先出的行为。(栈是是为了函数调用)。
esp : 栈顶指针
ebp : 函数调用返回地址指针
每次新的活动记录对应的栈地址地址都不是固定的,这样保证了程序的安全性。
下面以一个函数调用过程介绍栈的变化:
从上面的过程我们可以得出结论:
函数的返回只是修改了ebp 和esp的值,并没有改变栈空间的数据。
实际开发中不能返回局部变量的地址 局部数组的数组名。因为这片数据已经没有什么意义了。
#include <stdio.h>
int* g()
{
int a[10] = {0};
return a;
}
void f()
{
int i =0;
int b[10] = {0, 1,2,3,4...10};
int* pointer = g(); // 调用之后这边空间释放了
for(i=0; i<10; i++)
{
b[i] = pointer[i]
}
for(i=0; i<10; i++)
{
printf("%d\n", b[i]);
}
}
int main()
{
f();
return 0;
}
//这样编译有警告,b[i]结果为都是0
// 验证栈空间里面的值会被改变的,进行如下修改
void f()
{
int i =0;
int b[10] = {0, 1,2,3,4...10};
int* pointer = g();
for(i=0; i<10; i++)
{
printf("%d\n", pointer[i]);
}
}
// 编译有警告,这样结构为随机值
分析:
p指针里面的值在g()没有返回时确实都是0, 但是由于g() 函数返回,对应的活动记录被释放了,程序后面调用printf 函数 建立一个新活动记录,p指向活动记录的值被改变。P就是野指针。
堆区
堆是程序中一块预留的内存空间,可由程序自由使用(因为程序运行时需要临时的一片内存空间)(因为不能从栈上返回)
堆中被程序申请使用的内存在被主动释放前将一直有效。
问题:需要堆的的原因
栈上的数据在函数返回后就会被释放掉,无法传递到函数外部,比如 局部数组。
空闲链表法是导致malloc申请的内存比实际多的原因,是按照最接近的内存大小进行分配。
静态存储区
(主要用于保存全局变量和静态局部变量)(在程序运行那一刻就被系统分配出来了)在程序里面是有固定的起始地址的 ,所以一些变量是有连续的地址的,生命周直到程序运行结束,并且程序在编译器静态存储区的大小就已经确定。
#include <stdio.h>
int g_v = 1;
static int g_vs = 2;
void f()
{
static int g_vl = 3;
printf("%p\n", &g_vl);
}
int main()
{
printf("%p\n", &g_v);
printf("%p\n", &g_vs);
f();
return 0;
}
实验发现这几个内存是相邻的,说明都在静态存储器空间里面
小结:
栈,堆,静态存储区是程序的三个基本数据区
栈区主要用于函数调用的使用
堆区主要用于内存的动态申请和归还
静态存储区用于保存全局变量和静态变量