程序中的栈:
栈是现代计算机程序里最为重要的概念之一
栈在程序中用于维护函数调用上下文
函数中的参数和局部变量存储在栈上
栈保存了一个函数调用所需的维护信息
参数、返回地址、局部变量、调用上下文。。。
以栈的方式记录活动信息
调用函数的活动记录位于 栈的中部
被调函数的活动记录位于栈的顶部
函数调用栈的变化:
通过层级调用,来存储调用时候的数据信息、返回地址、参数等
ebp用来标记函数返回
不要返回局部变量的地址(局部数组的数组名)的原因就在于 栈空间的数据是有顺序的,因为数据不会由于函数返回而改变,但是函数返回后又重新调用新的函数后,空间中的数据已经改变。本想调用的数据已经被改变。
函数调用栈上的数据:
函数调用时, 对应的栈空间在函数返回前是专用的函数调用结束后,栈空间将被释放,数据不再有效
#include <stdio.h>
int* g()
{
int a[10] = {0};
return a;
}
void f()
{
int i=0;
int b[10] = {0,1,2,3,4,5,6,7,8,9};
int* pointer = g(); //野指针; g返回后,活动记录已经消失,对应的值虽然还在,
/*
for(i=0; i<10; i++)
{
b[i] = pointer[i];
}
*/
for(i=0; i<10; i++)
{
printf("%d\n", pointer[i]);//printf()函数建立新的活动记录,会将g()活动记录里面的值改变
//printf("%d\n", b[i]);
}
}
int main()
{
f();
return 0;
}
编译运行:
~/will$ gcc test.c
test.c: In function ‘g’:
test.c:7: warning: function returns address of local variable
~/will$ ./a.out
0
10874868
0
0
-1076000920
9755680
-1076000840
9755680
10876128
134514000
程序中的堆:
堆是程序中一块预留的内存空间,可由程序自由使用
堆中被申请使用的内存在被主动释放前将一直有效
有栈为什么还需要堆呢?
栈上的数据在函数返回后就会被释放掉,无法传递到函数外部,如:局部数组
程序运行的过程中,需要的临时空间不能存在于栈上,因为函数调用的过程中,局部变量的空间会被覆盖,
所以需要堆空间,在主动释放前不会被占用。
系统对堆空间的管理方法:
空闲链表法 (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;
}
编译运行:
~/will$ ./a.out
0x804a014
0x804a018
0x804a01c
说明程序中的三个变量是存储在一起的。(静态存储区有固定的起始地址)
小结:
栈、堆和静态存储区是程序中的三个基本数据区
栈区主要用于函数调用
堆区主要用于内存的动态申请和归还
静态存储区用于保存全局变量和静态变量