zoukankan      html  css  js  c++  java
  • 局部变量&&malloc函数&&生命周期的一些见解

    最近在温习指针的部分时发现了一个有趣的问题,先看以下程序:

    //1.c
    #include<stdio.h>
    int* fun()
    {
        int t = 567;
        return &t;
    }
    int main()
    {
        int *p;
        p = fun();
        printf("%d",*p);
    }
    

    当我把1.c运行后,发现输出结果是:567。此时编译器给出警告信息:返回值是局部变量的地址。

        首先,我们知道操作系统给函数分配的内存空间都是在栈中,当函数调用结束后,操作系统就会回收其内存空间。当然,这个过程包括回收函数内部的局部变量(局部变量也是存储在栈空间中),而此处的"回收"是指销去变量名/函数名,并把其内存空间标记为可用。即操作系统可对该部分内存空间重新利用。但既然变量已经被回收了,为什么还能输出其值?

      对于此问题,我是这样认为的:

    1.当变量的生命周期结束后,虽然变量该变量已不存在,但其之前分配的内存空间还在,也就是其地址还是之前变量的地址,而如果该部分内存空间在main函数结束之前都一直未被操作系统重新利用的话,它的数据没有被改写,那么此时输出*p的值还是之前变量的值。

    2.虽然我输出的*p是567,但是不能保证每次输出的*p都是567。因为编译器和操作系统都无法保证这部分内存空间在main函数结束前一直都不会被利用,所以这种输出是不稳定的。实际上,此时的指针p相当于一个野指针,此时虽然也可以对这部分内存空间进行读写操作(可看作对野指针的操作),但是相当危险的。

    3.由此可知,一定不要把局部变量的地址作为函数的返回值。

    接下来再看另一个程序:

    //2.c
    #include<stdio.h>
    #include<stdlib.h>
    int* fun()
    {
        int *t = (int*)malloc(sizeof(int)); ;
        *t = 567;
        return t;
    }
    int main()
    {
        int *p;
        p = fun();
        printf("%d",*p);
    }
    

      

    当我运行2.c后,发现其输出结果:567。并且编译器没有给出任意的警告信息。

    此时t作为一个局部变量,并且函数的返回值为t的地址,为什么编译器没给出警告?

    在我看来,2.c中的t与1.c中t虽然同为局部变量,两者在内存中的分布是完全不同的。1.c中的t是存储在栈空间中的,而2.c中t是存储在堆空间中的(堆与栈的区别:http://www.cnblogs.com/wangkundentisy/articles/6003482.html)。而当局部变量生命周期结束后,编译器会先消除该局部变量名,然后对于栈中的空间,编译器会释放它;而对于堆中的空间,编译器并不理会。所以,在2.c中,虽然fun函数以及指针t被销毁,但t指向的内存空间依然完好无损,并且由于编译器并未释放它,操作系统自然不会去利用这部分内存空间。所以,最后输出*p时,始终会输出567。但是,这样会造成内存泄漏,并产生垃圾!所以说malloc之后,一定要有一个free与之相对应!故在2.c中,printf函数后应加上free(p)。

      综上,在写程序时,一定不要把局部变量的地址作为函数的返回值!一定尽量避免返回在函数内部使用的分配函数(malloc或new)分配的内存空间,以及malloc和free一定要成对的出现!

  • 相关阅读:
    linux嵌入式系统交叉开发环境
    Codeforces Round #208 E. Dima and Kicks
    mvn 编译错误java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter. <init>(Z)V
    黑马程序员_<<TCP>>
    微信/易信公共平台开发(四):公众号调试器 (仿真微信平台,提供PHP源码)
    用pdb调试OpenStack Havana
    MySql Odbc等驱动下载地址分享下
    导入exce表格中的数据l到数据库
    关闭数据备份信息写入数据库日志
    SQL Server之RAID简介
  • 原文地址:https://www.cnblogs.com/wangkundentisy/p/6087499.html
Copyright © 2011-2022 走看看