时间:2022-08-16 12:38:11 | 栏目:C代码 | 点击:次

栈保存了一个函数调用所需的维护信息

每次函数调用都对应着一个栈上的活动记录

从main() 开始运行

main() 调用 f()

当从 f() 调用中返回 main()


下面看一个指向栈数据的指针:
#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();
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;
}
输出结果如下:

如果把
for (i = 0; i < 10; i++)
{
b[i] = pointer[i];
}
注释了,直接打印 pointer[i] 里面的数据,如下:
#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();
/*
for (i = 0; i < 10; i++)
{
b[i] = pointer[i];
}
*/
for(i = 0; i < 10; i++)
{
printf("%d\n", pointer[i]);
}
}
int main()
{
f();
return 0;
}
输出结果如下:

为什么直接打印 pointer[i] 里面的值会是这样呢?因为 pointer 指向的空间是栈空间,栈空间在 g() 函数返回之后,活动记录就被释放了。被释放后调用 printf 函数,printf 函数需要在栈上面建立一个活动记录。这个活动记录就会有 printf 函数的参数信息和返回值等,所以 pointer 所指向的内存里面的数据由于 printf 函数的调用被改变了。因此,不能返回局部变量的地址,不能返回局部数组的数组名。
为什么有了栈还需要堆?
答:栈上的数据在函数返回后就会被释放掉,无法传递到函数外部,如:局部数组
C语言程序中通过库函数的调用获得堆空间
系统对堆空间的管理方式
空闲链表法,位图法,对象池法等等

以 int* p = (int*)malloc(sizeof(int)); 为例,要申请 4 个字节的大小,遍历之后发现跟 5 Bytes 这个节点最接近,找到一个可以用的单元之后,就将这个单元的地址返还给了 p 指针。以前也提过使用 malloc 申请内存空间时返回的内存空间可能比申请的实际内存空间要大一点点,原因就是在空闲链表管理堆空间这样的系统里面,它会找最近的那个,找到后的一般都大于等于所需要的内存空间,假如 5 Bytes 这个节点下所有的空闲内存单元都用完的话,就会找 12 Bytes 节点下的内存单元,这样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;
}
输出结果如下:

可以看到这三个地址是顺序存放的,因为这三个变量都是存放在程序的静态存储区,静态存储区在程序里面有固定的起始地址。
栈,堆和静态存储区是程序中的三个基本数据区