博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据的存储区域
阅读量:6324 次
发布时间:2019-06-22

本文共 3216 字,大约阅读时间需要 10 分钟。

参考文章

存储区域

  1. 全局区域(静态区域,程序结束后由 os 释放)

    • 全局已初始化区域(已初始化全局变量 + 未初始化静态变量)
    • 全局未初始化区域(未初始化全局变量 + 未初始化静态变量)
  2. 栈区(由编译器自动分配释放)

    • 函数参数、局部变量、函数返回值等
  3. 堆区(由程序员分配释放)

    • 通过 malloc、calloc、realloc 分配的内存
  4. 文字常量区(程序结束后由系统释放 )

    • 常量字符串就是放在这里的

目前已知且自认为能够理解的存储区域就以上四种,其他的待补。

实践证明

1. 全局区域

在外部声明的变量以及静态变量是存放在全局区域的。

已初始化全局变量、已初始化静态变量在同一个区域,如下范例将证明这一点:

int a = 10;int a1 = 11;int a2 = 12;void main(void){    printf("a = %p\n" , &a);   // 假设 &a  = 0x000f24    printf("a1 = %p\n" , &a1);  // 则  &a1 = 0x000f28    printf("a2 = %p\n" , &a2);  // 则  &a2 = 0x000f2c        // 以下是干扰的变量    int b = 10;    int b1 = 11;    int b2 = 12;        printf("b  = %p\n" , &b);  // 可以查看该部分干扰变量的地址    printf("b1 = %p\n" , &b1); // 和之前的全局 a a1 a2 或 之后的 a3 a4    printf("b2 = %p\n" , &b2); // 变量地址完全不在同一频道上        // 静态变量    static int a3 = 13;    static int a4 = 14;         printf("a3 = %p\n" , &a3); // 0x000f30,地址紧接在全局变量a2地址后,证明统一区域    printf("a4 = %p\n" , &a4)  // 0x000f34}

未初始化全局变量、未初始化静态变量在同一个区域,以下范例证明(验证方式同上):

int a;int a1;int a2;void main(void){    printf("&a  = %p\n" , &a);    printf("&a1 = %p\n" , &a1);    printf("&a2 = %p\n" , &a2);        // 干扰变量    int b;    int b1;        printf("\n");        static a3;    static a4;        printf("&a3 = %p\n" , &a3);    printf("&a4 = %p\n" , &a4);}

2. 栈区

函数参数,函数内部局部变量在内存中的的栈区。

int test(int a , int b){    // a,栈区    // b,栈区    // a + b 的结果,栈区    return a + b;}void main(void) {    int a = 10; // 栈区    int b = 10; // 栈区    const int a = 10; // 栈区    int *p = &a; // 栈区    int *const p1 = &a; // 栈区        int c = test(); // 栈区}

3. 堆区

使用 malloc、calloc、realloc 分配的内存空间属于堆区。

void main(void) {    int len = 2; // 栈区    int *p = (int *)malloc(len * sizeof(int)); // p 在栈区,malloc 分配的内存在堆区!        int i = 0; // 栈区        for (; i < len; ++i)    {        printf("请输入成绩:");        scanf_s("%d" , p + i); // p + i 指向的内存地址在堆区,数据保存在堆区    }        // 输出成绩总和    int c = 0; // 栈区        for (i = 0; i < len; ++i)    {        // 输出用户输入的成绩        printf("成绩%d = %d\n" , i , *(p + i));        c += *(p + i);   // c 栈区,p 栈区, *(p + i) 堆区    }        printf("总成绩 = %d\n" , c);         system("pause");}

应用

上述知识有什么用呢??请看如下范例:

栈区 有关的

int * test(){    int arr[2] = {1 , 2};        return arr;}void main(void){    int *p = test();        printf("arr[0] = %d\n" , *p);       // 1    printf("arr[1] = %d\n" , *(p + 1)); // -858993460}

为什么会出现这样的现象呢??这就和内存的存储区域有关了!

test 函数内的相关变量存放在栈区,所以他们由编译器自动分配释放,即:他们会在函数调用完毕后释放,注意:释放不是销毁,只是放弃对栈区的使用权,即栈区内存区域允许被其他数据覆盖!

test 执行完毕后,栈区释放。第一次调用 printf 的时候,在还没有进入 printf 之前获取 *p 的值,此时栈区数据还在,没有被其他数据覆盖,然后被拷贝一份副本当做变元给 printf 当第一个参数,正确输出,输出完毕后,栈区被破坏(数据被覆盖了,不然放着老数据占用内存肯定是不行的),所以第二次调用 printf 输出 *(p + 1) 的时候,结果未知,就是因为 p + 1 指向的栈区数据已经被销毁了。


堆区 有关的,请看下面的范例:

int * test(void){    int *p = (int *)malloc(2 * sizeof(int));        *p = 1;    *(p + 1) = 2;        return p;}void main(void) {    int *p = test();        printf("*p = %d\n" , *p); // 1    printf("*(p + 1) = %d\n" , *(p + 1); // 2}

通过 malloc 分配的内存区域在堆区。所以在 test 函数调用完毕后,分配的 2 * sizeof(int) Byte空间没有被释放,因而通过 *p、*(p + 1) 能够正确访问数据。


文字常量区 有关的,请看下面的范例:

char * test(void){    char *str = "test";    return str;}void main(void) {    char *p = test();        printf("%s\n" , *p);    printf("%s\n" , *p);}

字符串 "test" 是存放在 文字常量 区的,所以在 test 函数调用完毕后,其并没有被释放,因而两次调用printf 都能正确输出。

转载地址:http://zxmaa.baihongyu.com/

你可能感兴趣的文章
在CentOS6上编译安装http2.4
查看>>
Pycharm安装pip pip安装第三方模块
查看>>
cobbler安装centos 7系统
查看>>
curl 命令
查看>>
XP系统开机提示"NTLDR is missing" 的解决方法
查看>>
【C#小知识】C#中一些易混淆概念总结(五)---------深入解析C#继承
查看>>
JavaScript琐记
查看>>
MAK代理激活的使用方法和注意事项
查看>>
sed用法
查看>>
针对web高并发量的处理
查看>>
Vbs脚本编程简明教程之三
查看>>
IT服务管理的指挥与智慧
查看>>
每天一个知识点linux(十一)任务计划
查看>>
ACL与磁盘配额结合应用小结
查看>>
基于LinuxOPENldap实验之账户管理
查看>>
交换机上配置PVST
查看>>
多程序集版本冲突问题
查看>>
MariaDB九之基于mysql-porxy实现读写分离
查看>>
OC异常处理
查看>>
【android工程转为lib工程后提示'R.id.xxx不能作为case语句的表达式'的解决办法】...
查看>>