目錄
1 C語言的內(nèi)存分區(qū)
1.1 內(nèi)存五大分區(qū)
1.2 內(nèi)存分區(qū)簡介
1.2.1 棧區(qū)(stack)
1.2.2 堆區(qū)(heap)
1.2.3 (全局)靜態(tài)區(qū)
1.2.4 常量區(qū)
1.2.5 代碼區(qū)
創(chuàng)作不易,如果本篇博客對您有一定的幫助,大家記得留言+點贊哦。
C語言已經(jīng)持續(xù)學(xué)習(xí)一段時間了,今天特此總結(jié)一下關(guān)于C語言內(nèi)存的五大區(qū)。它是我們深入理解C語言非常有必要了解的知識點。通過了解五大區(qū),對于進一步學(xué)習(xí)C語言底層是非常有幫助的。
1 C語言的內(nèi)存分區(qū)
1.1 內(nèi)存五大分區(qū)
C語言內(nèi)存可大致分為5個區(qū)域,圖和表如下:
內(nèi)存影像區(qū) | 內(nèi)容 | ?權(quán)限 |
棧區(qū) | 函數(shù)中的普通變量 | 可讀可寫 |
堆區(qū) | 動態(tài)申請的內(nèi)存 | 可讀可寫 |
(全局)靜態(tài)變量區(qū) | static修飾的變量 | 可讀可寫 |
常量區(qū) | 用于初始化變量的常量 | 只讀 |
代碼區(qū) | 代碼指令 | 只讀 |
nt k=1;
void main()
{
int i=1;
char *j;
static int m=1;
char *n="hello";
printf("棧區(qū)地址為:0X%x\n",&i);
j = (char*)malloc(2); //一般不確定需要多大空間的時候用
free(j);//及時釋放
printf("堆區(qū)地址為:0X%x\n",j);
printf("全局變量地址為:0X%x\n",&k);
printf("靜態(tài)變量地址為:0X%x\n",&m);
printf("文字常量區(qū)地址為:0X%x\n",n);
printf("程序區(qū)地址為:0X%x\n",&main);
}
char *i="hello";
char j[10]="hello";
printf("0X%x\n",i); //存放在文字常量區(qū)
printf("0X%x\n",j); //存放在棧區(qū)
j[1]='*';//可以直接賦值
//*(i+1)='*'; //等價于i[1]='*';
//不可以這樣賦值, 因為i是指針,指向的是文字常量區(qū),里面的內(nèi)容是不能修改的
i=j; //這樣可以
printf("%s\n",i);
printf("%x\n",i);
j=i;//這樣不可以,因為j雖然也是地址,但是不是指針變量,不能直接賦值
1.2 內(nèi)存分區(qū)簡介
1.2.1 棧區(qū)(stack)
棧區(qū)
由編譯器自動分配釋放,由操作系統(tǒng)自動管理,無須手動管理。
棧區(qū)上的內(nèi)容只在函數(shù)范圍內(nèi)存在,當(dāng)函數(shù)運行結(jié)束,這些內(nèi)容也會自動被銷毀。
#include<stdio.h>
char *getMem()
{
char buf[64]; //局部變量 棧區(qū)存放
strcpy(buf, "123456789");//向buf所代表的內(nèi)存中寫入內(nèi)容
//printf("buf:%s\n", buf);
return buf;//返回所分配內(nèi)存區(qū)域的第一個元素的地址
}
void main()
{
char *tmp = NULL;
tmp = getMem(10);
if (tmp == NULL)
{
return ;
}
printf("tmp:%s\n", tmp);//輸出tmp:
system("pause");
return ;
}
內(nèi)存分析:
? ? ??
?
- 棧區(qū)按內(nèi)存地址
由高到低
方向生長,其最大大小由編譯時確定,速度快,但自由性差,最大空間不大。 - 棧區(qū)是
先進后出
原則,即先進去的被堵在屋里的最里面,后進去的在門口,釋放的時候門口的先出去。 -
棧區(qū)存放內(nèi)容
- 臨時創(chuàng)建的
局部變量
和const定義的局部變量
存放在棧區(qū)。 -
函數(shù)調(diào)用和返回時,其
入口參數(shù)
和返回值
存放在棧區(qū)。
通俗來說:
棧區(qū)是用來存放局部變量的,比如函數(shù)內(nèi)部定義的int a,int b,const int a,char p,char arr[ ],還有函數(shù)的形參等等都是存放在棧區(qū)。棧區(qū)的數(shù)據(jù)由編譯器管理,調(diào)用完之后就自動釋放,壓棧,出棧。先進后出的原則,比如當(dāng)你執(zhí)行到函數(shù)調(diào)用的時候,編譯器會先把下一條代碼的地址壓入棧中,再把你調(diào)用的那個函數(shù)里的一些局部變量啊,形參啊等等壓入棧中,等你函數(shù)調(diào)用執(zhí)行完畢。棧就會把你調(diào)用的這個函數(shù)之前壓入棧的變量和形參全部清除出棧,之后根據(jù)下一條代碼的地址,接著執(zhí)行程序,以后的程序也都是這么執(zhí)行。棧區(qū)是有大小的,一般是1M左右,所以別定義太大的數(shù)組。
?
1.2.2 堆區(qū)(heap)
堆區(qū)
由程序員分配內(nèi)存和釋放。若程序員不釋放,程序結(jié)束時可能由操作系統(tǒng)回收。
#include <stdio.h>
char *getMem(int num)
{
char *p1 = NULL;
p1 = (char *)malloc(sizeof(char) * num);
if (p1 == NULL)
{
return NULL;
}
return p1;
}
void main()
{
char *tmp = NULL;
tmp = getMem(10);
if (tmp == NULL)
{
return ;
}
strcpy(tmp, "111222"); //向tmp做指向的內(nèi)存空間中copy數(shù)據(jù),注意不是向指針變量tmp中
printf("tmp:%s\n", tmp);//輸出tmp:111222
system("pause");
return ;
}
內(nèi)存分析:
? ? ? ??
?
- 堆區(qū)按內(nèi)存地址
由低到高
方向生長,其大小由系統(tǒng)內(nèi)存/虛擬內(nèi)存上限決定,速度較慢,但自由性大,可用空間大。
堆區(qū)動態(tài)申請與釋放內(nèi)存
用malloc()
,free()
等函數(shù)實現(xiàn)動態(tài)分布內(nèi)存。
void *malloc(size_t);
- 參數(shù)
size_t
是分配的字節(jié)大小; - 返回值是一個
void*
型的指針,該指針指向分配空間的首地址;
(void *
型指針可以任意轉(zhuǎn)換為其他類型的指針)
用free()
函數(shù)進行內(nèi)存釋放,否則會造成內(nèi)存泄漏。
void free(void * /*ptr*/);
- 參數(shù)
ptr
是開辟的內(nèi)存的首地址。 - 無返回值;
通俗來說:
由程序員手動申請和釋放
比如:int?p=(int?)malloc(sizeof(int)10),表示申請了一塊40個字節(jié)的堆區(qū)空間,然后申請完記得用free釋放。
代碼區(qū)的話就是用來存放代碼的,轉(zhuǎn)化為二進制存放。
1.2.3 (全局)靜態(tài)區(qū)
通常是用于那些在編譯期間就能確定存儲大小的變量的存儲區(qū),但它用于的是在整個程序運行期間都可見的全局變量
和靜態(tài)變量
。
全局區(qū)有?.bss段
?和?.data段
組成,可讀可寫
。
#include <stdio.h>
char * getStr1()
{
char *p1 = "abcd";
return p1;
}
char *getStr2()
{
char *p2 = "abcd";
return p2;
}
void main()
{
char *p1 = NULL;
char *p2 = NULL;
p1 = getStr1();
p2 = getStr2();
//打印p1 p2 所指向內(nèi)存空間的數(shù)據(jù),不是p1 p2中的數(shù)據(jù)
printf("p1:%s , p2:%s \n", p1, p2);//輸出p1:abcd , p2:abcd
//打印p1 p2 的值
printf("p1:%d , p2:%d \n", p1, p2);//輸出p1:19184372 , p2:19184372
system("pause");
return;
}
內(nèi)存分析:
? ? ? ? ?
?
-
.bss段
未初始化的全局變量和未初始化的靜態(tài)變量存放在.bss段。
初始化為0的全局變量和初始化為0的靜態(tài)變量存放在.bss段。
.bss段不占用可執(zhí)行文件空間,其內(nèi)容由操作系統(tǒng)初始化。 -
.data段
已初始化的全局變量存放在.data段。
已初始化的靜態(tài)變量存放在.data段。
.data段占用可執(zhí)行文件空間,其內(nèi)容有程序初始化。
通俗來說:
全局區(qū)比較特殊,里面還分成了全局變量區(qū),靜態(tài)變量區(qū),常量區(qū)。全局變量區(qū)用來存放全局變量,靜態(tài)變量區(qū)用來存放帶有static修飾的變量(包括靜態(tài)局部變量和靜態(tài)全局變量),只要含有static就存在這個區(qū)。常量區(qū)是用來存放字符常量的,還有const修飾的全局變量的,const 修飾的局部變量不存在這里,別搞混了。全局區(qū)存放的一切都是由操作系統(tǒng)管理,等程序結(jié)束由操作系統(tǒng)釋放。常量區(qū)里存放的數(shù)據(jù)不可更改,就算你用指針也不行,你可能會說const修飾的局部變量都可以用指針改,但是局部變量可不是存放在常量區(qū),這點搞清楚。
1.2.4 常量區(qū)
字符串
、數(shù)字
等常量存放在常量區(qū)。const
修飾的全局變量存放在常量區(qū)。
程序運行期間,常量區(qū)的內(nèi)容不可以被修改。
1.2.5 代碼區(qū)
程序執(zhí)行代碼
存放在代碼區(qū),其值不能修改(若修改則會出現(xiàn)錯誤)。字符串常量
和define定義的常量
也有可能存放在代碼區(qū)。
? ? ? ? 以上五區(qū),代碼區(qū)和全局區(qū)是在生成.exe文件之后就有了,雙擊.exe文件運行程序才會生成棧區(qū)和堆區(qū)。
下面直接上圖:
#include<stdio.h>
#include<string.h>
int a = 10;
static int b = 20;
void fun(int x)
{
char *p = "Hello";
printf("形參x的地址=%d\n\n", &x);
printf("Hello的地址=%d\n\n", "Hello");
printf("指針變量p的地址=%d\n\n", &p);
return;
}
int main(int argc,const char *argv[])
{
int c = 10;
int d = 20;
static int e = 30;
char *p = "Hello";
printf("\n全局變量a的地址=%d\n\n", &a);
printf("靜態(tài)全局變量b的地址=%d\n\n", &b);
printf("靜態(tài)局部變量e的地址=%d\n\n", &e);
printf("字符串\"Hello\"的地址=%d\n\n", "Hello");
printf("局部變量c的地址=%d\n\n", &c);
printf("局部變量d的地址=%d\n\n", &d);
printf("指針變量p的地址=%d\n\n", &p);
fun(5);
system("pause");
return 0;
}
文章來源:http://www.zghlxwxcb.cn/news/detail-602525.html
?簡單的用圖表示了一下,總結(jié):
全局區(qū)存放的是全局變量,靜態(tài)變量,字符常量,const 修飾的全局變量。棧區(qū)存放的是局部變量和函數(shù)的形參,以及一些代碼的地址,棧區(qū)的內(nèi)容是可以修改的
堆區(qū)是由程序員手動申請和釋放,用malloc函數(shù)申請,用free函數(shù)釋放。文章來源地址http://www.zghlxwxcb.cn/news/detail-602525.html
創(chuàng)作不易,如果本篇博客對您有一定的幫助,大家記得留言+點贊哦。
到了這里,關(guān)于【C語言】-- 一篇帶你了解C語言內(nèi)存五大區(qū)——棧區(qū),堆區(qū),全局區(qū),常量區(qū),代碼區(qū)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!