上次分享c语言中内存四区的相关知识,这边再补充一下栈的生长方向和数组的生长方向是什么样的?
这边可以做个验证,可以先假定往上的内存地址是较大的,先在栈上开辟两块空间,如果先申请的内存地址较小的话就说明栈的开口方向是向上的,因为栈是先进后出的,如果先申请的的内存地址较大的话就说明开口是向下的。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//堆
char *getMem(int num)
{
char *p1 = NULL;
p1 = (char *)malloc(sizeof(char)*num);
if (p1 == NULL)
{
return NULL;
}
return p1;
}
//栈
char *getMem2()
{
char buf[64] = { 0 };
strcpy(buf, "123456789");
return buf;
}
int main(int argc, char *argv[])
{
//char *tmp = NULL;
//tmp = getMem(10);
//if (tmp == NULL)
//{
// return -1;
//}
//strcpy(tmp, "1111222");//向tmp所指向的内存空间中copy数据
//
//printf("heap:getMem:%s\n", tmp);
//tmp = getMem2();
//printf("stack:getMem:%s\n", tmp);
int a;
int b;
//不管栈的开口向上还是向下,buf的内存地址buf+1永远是向下
char buf[128];
printf("&a:%d,&b:%d\n", &a, &b);
system("pause");
return 0;
}
可以看到b的地址是小于a的,所以证明该编译器的栈开口是向下的。
但是对于数组来说buf+1的地址都是大于buf的地址的,所以数组的生长方向和栈的生长方向是不一样的。
下面来说一下函数调用的模型。
我们可以看到当主函数调用其他函数的时候就会出现类似中断的机制,先将子函数的参数入栈,然后就先执行子函数,然后执行析构销毁掉子函数分配的栈内存。
这边需要注意的是,如果在子函数里面分配的堆和栈内存,在fa和fb中是可以使用的。
如果是fa在栈中分配的内存在main函数中是不能使用的,但是在fb函数中是可以使用的,因为在执行完fa函数后,fa在栈空间中的内存就被释放了,所以在main函数中无法使用,但是如果过是在堆区里面分配的空间,例如在fb函数内分配的堆空间,在main函数和fa函数中都可以使用,因为堆内存是在程序结束后会释放的。