局部變量&&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一定要成對的出現!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM