C/C++程序佔用的內存分爲兩大類:靜態存儲區
與動態存儲區
。其示意圖以下所示:git
數據保存在靜態存儲區與動態存儲區的區別就是:靜態存儲區在編譯-連接
階段已經肯定了,程序運行過程當中不會變化,只有當程序退出的時候,靜態存儲區的內存纔會被系統回收。動態存儲區是在程序運行過程當中動態分配的。github
在其它地方咱們還能夠看到內存分配還有其餘分類,那些都是細分的分類,好比文字常量區、全局數據區等,都歸爲靜態存儲區這一個大類。數組
關於內存的分類這裏只是大體說明一下,關於內存更詳細的內容可查看往期筆記:微信
先看一個return返回指向棧內存指針的例子:指針
#include <stdio.h> char *GetStr(void) { char p[] = "Hello"; /* 保存在棧中 */ return p; } int main(void) { char *str = NULL; str = GetStr(); printf("%s\n", str); return 0; }
程序編譯、運行的結果以下:code
能夠看到,編譯出現警告:blog
warning: function returns address of local variable內存
運行結果並非咱們指望的輸出字符串Hello
。字符串
那是由於GetStr
函數返回指向棧內存的指針,這裏的變量p是局部變量,而局部變量是分配在棧上的。即Hello
保存在棧內存上,棧內存在函數調用結束時會自動銷燬,所以此時的p裏的內容是未知的,因此結果無輸出。
下面咱們把GetStr
函數修改成:
char *GetStr(void) { char *p = "Hello"; /* p在棧上,Hello在靜態區(常量區) */ return p; }
此時編譯運行的結果是怎樣的呢?結果爲:
能夠看到能正常輸出。爲何這裏又能夠正常輸出呢?由於這裏的p雖然分配在棧上,可是此時的Hello
是一個字符串常量,其存儲在靜態存儲區。在調用GetStr
函數結束時其也不會被銷燬。
這裏可能有些人會有疑惑,一樣是Hello
,爲何一個在棧上,一個在靜態區。
char *p = "Hello";
此處首先定義了一個指針變量p,編譯器就會爲指針變量開闢了棧空間。而此時並無空間來存放Hello
,因此Hello
只能存儲在靜態區。
char p[] = "Hello";
此處首先定義一個數組p,由於未給出數組大小,因此此時數組大小未肯定。而後把Hello
保存在這個數組裏,編譯器就會爲數組p開閉適當的棧空間來存儲Hello
。
相關筆記:【C語言筆記】char *str與char str[]的區別
從上面的例子咱們知道,若函數返回指向棧內存的指針,所獲得的結果並非咱們想要的。除了上面的方法以外,這裏還有以下幾種解決方法:
一、把p定義爲全局變量,由於全局變量存儲在靜態存儲區,程序結束纔會釋放。可是這樣會致使函數是不可重入的。關於函數的重入與不可重入可查看往期筆記。
二、在GetStr
函數中使用malloc
申請動態內存,但使用完必定要記得使用free
進行釋放,不然會致使內存泄漏。示例代碼以下:
#include <stdio.h> #include <stdlib.h> #include <string.h> char *GetStr(void) { char *p = (char*)malloc(64*sizeof(char)); strcpy(p, "Hello"); return p; } int main(void) { char *str = NULL; str = GetStr(); printf("%s\n", str); free(str); /* 釋放str指向的堆內存 */ return 0; }
三、能夠將變量p聲明爲static靜態變量。但這也會致使函數是不可重入的。示例代碼以下:
char *GetStr(void) { static char p[] = "Hello"; return p; }
以上就是本次筆記分享的內容,若有錯誤,歡迎指出!
個人我的博客:https://zhengnianli.github.io/ 個人微信公衆號:嵌入式大雜燴