1)代碼區:可執行程序代碼存放區,這個咱們不用關心;
2)全局區:
1全局與靜態變量區:存放全局變量與靜態變量,又能夠區分爲已經初始化的全局變量和靜態變量區以及爲初始化的全局變量和靜態變量區;
2常量區:字符串常量與const修飾的常量存放在常量區;數組
3)堆區:用戶動態申請的內存區,須要用戶進行釋放,不然有可能會形成內存泄漏;
4)棧區:該區內存由系統自動分配和釋放,存放局部變量以函數實參等。
1全局區分析
看一段代碼:ide
char *get_str() { char *p="abcd";//文字常量區 return p; } char *get_str1() { char *q="abcd";//文字常量區 return q; } int main() { char *p=NULL; char *q=NULL; p=get_str(); q=get_str1(); //%s,打印指針指向內存區域的內容 //%d打印p自己的值 printf("p=%s,p=%d\n",p,p); printf("q=%s,q=%d\n",q,q); return 0; }
運行結果:
緣由:
看圖,從主函數main開始,在棧區定義了兩個指針變量p、q爲空,佔4個字節;
下面調用get_str();函數返回地址,在get_str();函數中又定義了一個p這個p給主函數中的p目前沒有關係,在get_str();函數中把字符串abcd賦值給p,而abcd是在文字常量區定義的,假如地址爲oxaabb,只有程序結束,纔會被釋放。
有get_str();返回的是地址oxaabb給主函數中的p,指針指向誰,就把誰的地址賦給誰,因此當get_str();釋放後,主函數的p已經指向了文字常量區的abcd,一樣的原理,因爲get_str1()也是把相同的字符串abcd賦值給q,q也是指向文字常量區的0xaabb,因此他們兩個地址是相同的,固然如是在賦值的字符串不一樣,那地址必定不一樣。
賦值字符串不一樣時:函數
char *get_str() { char *p="abcd1";//文字常量區 return p; } char *get_str1() { char *q="abcd2";//文字常量區 return q; } int main() { char *p=NULL; char *q=NULL; p=get_str(); q=get_str1(); //%s,打印指針指向內存區域的內容 //%d打印p自己的值 printf("p=%s,p=%d\n",p,p); printf("q=%s,q=%d\n",q,q); return 0; }
運行結果:指針
2棧區分析code
char *get_str2() { char str[]="abcd"; printf("str=%s\n",str); return str;//返回str數組的地址 } int main() { char buf[100]={0}; strcpy(buf,get_str2()); printf("buf = %s\n",buf); return 0; }
運行出錯。blog
char *get_str2() { char str[]="abcd"; printf("str=%s\n",str); return str;//返回str數組的地址 } int main() { //char buf[100]={0}; //strcpy(buf,get_str2()); char *p=NULL; p=get_str2(); // printf("buf = %s\n",buf); printf("p= %s\n",p); return 0; }
運行結果:
爲何p爲空那?
看圖,有於get_str2()函數調用完被釋放,str空間被回收,str空間的內容就未知,p指向就沒有了,p沒有指向會報錯或亂碼或爲NULL。注意這裏的char str[]="abcd";是賦值,並非指針的指向。
3堆區分析內存
char *get_str3() { //堆區手動分配空間 char *str=(char *)malloc(sizeof (char)*100); if(str==NULL)//分配失敗 { return NULL;//返回空 } //分配成功 strcpy(str,"abcd"); return str;//返回地址 } int main() { //char buf[100]={0}; //strcpy(buf,get_str2()); char *p=NULL; p=get_str3(); if(p!=NULL)//p不爲空 { printf("p= %s\n",p);//打印 free(p);//手動釋放 p=NULL;//賦值爲空 } // printf("buf = %s\n",buf); return 0; }
運行結果:
4函數調用模型
注:main函數在棧區開闢的內存,全部子函數均可以使用
main函數在堆區開闢的內存,全部子函數均可以使用
子函數開闢的棧區內存,只有其內部子函數才能使用
子函數在堆區開闢的內存,主函數與子函數內部的子函數均可以使用
子函數在全局區開闢的內存,主函數與子函數內部的子函數均可以使用字符串
5棧的生長方向和內存存放的方向get
int main() { int a; int b; printf("&a=%d,&a=%d\n",&a,&b);//棧區生長方向是向下的 char *p=(char *)malloc(10); char *q=(char *)malloc(10); printf("p=%d,q=%d\n",p,q); //堆區生長方向是向上的 int buf[4]; printf("&buf[0]=%d,&buf[1]=%d\n",&buf[0],&buf[1]); //數組生長方向是向上的 return 0; }
運行結果:it