C语言内存四区的学习总结(三)---- 栈区

接上篇内存四区的堆区的总结,下面做一些栈区的相关总结。

一、栈区的分析:

就下面测试程序

#include "stdio.h"
#include "string.h"
char *getMem()
{
    char buf[128];

    strcpy(buf, "aabbccdd");

    return buf;
}
int main(int argc, const char **argv)
{
    char *tmp = NULL;
    tmp = getMem2();
    printf("tmp = %s\r\n", tmp);
    return 0;
}
先进行程序的编译,会出现如下的警告:
​图1 编译警告说明示意图

警告说明的是返回局部变量或者临时变量的地址,暂时不管他,直接运行后出现效果:

​图2 运行的效果图

进行分析可知道其中的原委:

上面的程序,在getMem函数中,在栈区分配128字节的内存空间,在函数执行完毕返回后,将buf析构掉(浅粉色表示),并且,buf做指向的内存空间也被析构(灰色表示)。

其内存四区表示可以简单如图所示:

​图3 程序运行的内存四区的变化的模型示意图​​​​​

所以,在打印的时候出现不认识的东西,就是由于上述原因造成的。

二、堆栈的属性

1、栈的开口方向的测试(先进后出的特性)

可以简单的进行测试,首先假设一个虚拟的方向轴,那么,在图3所示的效果中,左边的栈一代表开口方向向下,右边栈二代表开口方向向上,那么,根据先进后出的特性,如果b的地址小,那说明栈的开口方向向下。

​图4 栈的开口方向的测试示意图

那么可以用下面的简单程序进行测试:

#include <stdio.h>

int main(int argc, const char **argv)
{
    int a;
    int b;
   
    printf("&a = %p, &b = %p\r\n", &a, &b);
    return 0;
}
编译运行后,可以看出来,a的地址为0060FF2C,大于b的地址0060FF28,那说明栈的开口方向是向下的。

其实在一般情况下,默认认为栈的开口向下的,主要是因为:每个应用程序的栈,如果提前把栈的最大值定义好,在程序逐渐入栈的过程中,栈的地址越来越小,避免栈的溢出。

​图5 运行效果图

2、栈的属性和内存块的地址增长方向是不同的概念

比如下面的测试程序。

#include <stdio.h>
int main(int argc, const char **argv)
{
    char buf[128];

    printf("buf = %p, buf + 1 = %p\r\n", buf, buf + 1);
    return 0;
}

​图6 内存块在栈区的示意图

如果buf指针指向绿色的位置,那么在进行buf+1运算的时候,指针就会跑到栈的外面去了,这不应该的出现的效果呀。和我们实际需要的buf+1的效果不一致。所以,不管栈的开口方向如何,内存块(buf)的内存空间的生长方向都是向上的。

运行我们的程序可以看出来:

​图7 运行的效果图

三、简单总结

1、拷贝指的是向指针指向的内存空间拷贝,而不是向指针变量中拷贝

2、程序返回的是指针的内存的首地址,而不是整个内存空间

3、一般情况下,默认认为栈的开口向下的

4、栈的属性和内存块的地址增长方向是不同的概念

posted @ 2019-04-09 09:37  我就叫宋帅呀  阅读(318)  评论(0编辑  收藏  举报