c內(nèi)存劃分

一攒菠、內(nèi)存分區(qū):數(shù)據(jù)區(qū)+代碼區(qū)+堆區(qū)+棧區(qū)
1、數(shù)據(jù)區(qū):分為靜態(tài)數(shù)據(jù)區(qū)歉闰,全局變量區(qū)的存儲是放在一塊的辖众。
即static,const修飾的變量和敬、常量凹炸、全局變量都定義在此區(qū),此區(qū)定義的變量未初始化昼弟,系統(tǒng)則會自動初始化為0
初始化的全局變量和靜態(tài)變量在一塊區(qū)域啤它, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域,程序結束后由系統(tǒng)釋放空間
const:修飾的變量只能讀不能修改他的值舱痘,表現(xiàn)的為一個常量的特性变骡。他只能在初始化的時候給他賦值,其他任何時候都不能給他賦值芭逝。
2塌碌、代碼區(qū):存放程序中的普通代碼(存放函數(shù)體的二進制代碼)。
3铝耻、堆區(qū)(heap):一般由程序員手動申請以及釋放, 若程序員不釋放蹬刷,程序結束時可能由OS回收 注意它與數(shù)據(jù)結構中的堆是兩回事瓢捉,分配方式類似于鏈表。
有malloc()/calloc()/recalloc()/new()來分配內(nèi)存办成,
生命周期有free()/delete()決定何時釋放分配的內(nèi)存泡态,此區(qū)使用靈活,空間相對較大迂卢。

4某弦、棧區(qū)(stack): 該區(qū)是有編譯器自動分配的一塊內(nèi)存區(qū)域桐汤,存放函數(shù)的參數(shù)值、局部變量的值等靶壮,甚至函數(shù)的調(diào)用過程都是用棧來完成怔毛,其操作方式類似于數(shù)據(jù)結構中的棧
    效率高,有編譯器自動分配和釋放(函數(shù)開始的時候分配腾降,結束的時候釋放)
5拣度、文字常量區(qū):常量字符串就是放在這里 程序結束后由系統(tǒng)釋放空間

下面的例子可以完全展示不同的變量所占的內(nèi)存區(qū)域:

//main.cpp

int a = 0; 全局初始化區(qū)
 char *p1; 全局未初始化區(qū)

void main()
 {
  int b; //棧中
  char s[] = "abc"; //棧中
  char *p2; //棧中
  char *p3 = "123456"; //123456\0在文字常量區(qū),p3在棧上
  static int c =0螃壤; //全局(靜態(tài))初始化區(qū)

//以下分配得到的10和20字節(jié)的區(qū)域就在堆區(qū)
  p1 = (char *)malloc(10);
  p2 = new char[20];//(char *)malloc(20);
  strcpy(p1, "123456"); //123456\0放在常量區(qū)抗果,編譯器可能會將它與p3所指向的"123456"優(yōu)化成一個地方
 }
注意:strcpy()函數(shù)用法:定義一個字符串char a[20],和一個字符串c[]="i am a teacher!";把c復制到a中就可以這樣用:strcpy(a,c);


char *p="zxcvbnm";
(p+1)='d';//修改第二個字符 因為p和“zxcvbnm”沒有保存在同一個區(qū),不能修改奸晴。斷錯誤
char *q="zxcvbnm"; //兩哥指針的地址相同
指針p 和指針 q都保存在棧區(qū)冤馏,但字符串zxcvbnm保存在文字常量區(qū),因為沒有保存在一個區(qū)寄啼,通過指針獲取某個字符是不對的
并且因為在文字常量區(qū)已經(jīng)開辟存放zxcvbnm的空間逮光,在賦值zxcvbnm的時候不會再開辟空間,會把第一次開辟的地址賦予他們辕录。


****手動在內(nèi)存上分配一塊空間:在堆上用malloc()函數(shù)分配一塊連續(xù)空間
函數(shù)原型:(void *)malloc(int size)
頭文件:malloc.h/stdlib.h
解析:內(nèi)存分配好了之后睦霎,malloc函數(shù)返回這塊內(nèi)存的首地址,默認為void *型走诞。故需要強制轉(zhuǎn)換成你需要的類型副女,括號里是您需要分配的內(nèi)存的字節(jié)數(shù)
例:char *p=(char *)malloc(100)
注:所申請的內(nèi)存必須小于堆上面某一整塊內(nèi)存,才能成功蚣旱,故malloc函數(shù)請一塊內(nèi)存有可能是不成功的碑幅,所以我們需要判斷一下他是否成功,
用if(NULL!=p)來驗證是否分配成功, 通常是成功的
****手動釋放動態(tài)內(nèi)存:
free(p)塞绿,同時沟涨,p=NULL;
釋放p所指向的那塊內(nèi)存异吻,這里雖然把p指向的那塊內(nèi)存給釋放掉了裹赴,但p的值仍沒有變,這個地址還是存在的诀浪,只是不能再訪問這個內(nèi)存棋返,所以再次使用它之前先要置NULL。


二雷猪、棧(stack)和堆(heap)具體的區(qū)別

1睛竣、在申請方式上
  棧(stack): 現(xiàn)在很多人都稱之為堆棧,這個時候?qū)嶋H上還是指的棧它由編譯器自動管理求摇,無需我們手工控制
例如射沟,聲明函數(shù)中的一個局部變量 int b 系統(tǒng)自動在棧中為b開辟空間殊者;在調(diào)用一個函數(shù)時,系統(tǒng)自動的給函數(shù)的形參變量在棧中開辟空間
  堆(heap): 申請和釋放由程序員控制验夯,并指明大小容易產(chǎn)生memory leak

在C中使用malloc函數(shù)

如:p1 = (char *)malloc(10);

在C++中用new運算符

如:p2 = new char[20];//(char *)malloc(10);

但是注意p1本身在全局區(qū)猖吴,而p2本身是在棧中的,只是它們指向的空間是在堆中

2簿姨、申請后系統(tǒng)的響應上

棧(stack):只要棧的剩余空間大于所申請空間距误,系統(tǒng)將為程序提供內(nèi)存,否則將報異常提示棧溢出
  堆(heap): 首先應該知道操作系統(tǒng)有一個記錄空閑內(nèi)存地址的鏈表扁位,當系統(tǒng)收到程序的申請時准潭, 會遍歷該鏈表,尋找第一個空間大于所申請空間的堆結點域仇,
然后將該結點從空閑結點鏈表中刪除刑然,并將該結點的空間分配給程序。另外暇务,對于大多數(shù)系統(tǒng)泼掠,會在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,
這樣垦细,代碼中的delete或free語句才能正確的釋放本內(nèi)存空間择镇。另外,由于找到的堆結點的大小不一定正好等于申請的大小括改,
系統(tǒng)會自動的將多余的那部分重新放入空閑鏈表中
  3腻豌、申請大小的限制

棧(stack):在Windows下,棧是向低地址擴展的數(shù)據(jù)結構,是一塊連續(xù)的內(nèi)存的區(qū)域嘱能。
這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預先規(guī)定好的吝梅,
在WINDOWS下,棧的大小是2M(也有的說是1M惹骂,總之是一個編譯時就確定的常數(shù))苏携,如果申請的空間超過棧的剩余空間時,將提示overflow
因此对粪,能從棧獲得的空間較小 例如右冻,在VC6下面,默認的椫茫空間大小是1M(好像是纱扭,記不清楚了)當然,我們可以修改:打開工程茫死,依次操作菜單如下:
Project->Setting->Link跪但,在Category 中選中Output履羞,然后在Reserve中設定堆棧的最大值和commit大的值峦萎,可能增加內(nèi)存的開銷和啟動時間屡久。

堆(heap): 堆是向高地址擴展的數(shù)據(jù)結構,是不連續(xù)的內(nèi)存區(qū)域(空閑部分用鏈表串聯(lián)起來)爱榔。正是由于系統(tǒng)是用鏈表來存儲空閑內(nèi)存被环,自然是不連續(xù)的,
而鏈表的遍歷方向是由低地址向高地址详幽,一般來講在32位系統(tǒng)下筛欢,堆內(nèi)存可以達到4G的空間,從這個角度來看堆內(nèi)存幾乎是沒有什么限制的由此可見唇聘,
堆獲得的空間比較靈活版姑,也比較大。

4迟郎、分配空間的效率上

棧(stack):棧是機器系統(tǒng)提供的數(shù)據(jù)結構剥险,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行宪肖,這就決定了棧的效率比較高
但程序員無法對其進行控制
  堆(heap):是C/C++函數(shù)庫提供的表制,由new或malloc分配的內(nèi)存,一般速度比較慢控乾,而且容易產(chǎn)生內(nèi)存碎片顯然么介,堆的效率比棧要低得多

5、堆和棧中的存儲內(nèi)容

棧(stack):在函數(shù)調(diào)用時蜕衡,第一個進棧的是主函數(shù)中子函數(shù)調(diào)用后的下一條指令(子函數(shù)調(diào)用語句的下一條可執(zhí)行語句)的地址壤短,然后是子函數(shù)的各個形參在大多數(shù)的C編譯器中,
參數(shù)是由右往左入棧的衷咽,然后是子函數(shù)中的局部變量鸽扁。
注意:靜態(tài)變量是不入棧的。 當本次函數(shù)調(diào)用結束后镶骗,局部變量先出棧桶现,然后是參數(shù),最后棧頂指針指向最開始存的地址鼎姊,
也就是主函數(shù)中子函數(shù)調(diào)用完成的下一條指令骡和,程序由該點繼續(xù)運行
  堆(heap):一般是在堆的頭部用一個字節(jié)存放堆的大小,堆中的具體內(nèi)容有程序員安排

6相寇、存取效率的比較

這個應該是顯而易見的拿棧上的數(shù)組和堆上的數(shù)組來說:

void main()
  {
  int arr[5]={1,2,3,4,5};
  int *arr1;
  arr1=new int[5];
  for (int j=0;j<=4;j++)
  {
  arr1[j]=j+6;

}
  int a=arr[1];
  int b=arr1[1];
  }

上面代碼中慰于,arr1(局部變量)是在棧中,但是指向的空間確在堆上唤衫,兩者的存取效率婆赠,當然是arr高,因為arr[1]可以直接訪問佳励,
但是訪問arr1[1]休里,首先要訪問數(shù)組的起始地址arr1蛆挫,然后才能訪問到arr1[1]


三、內(nèi)存的釋放:
學過C語言的都知道妙黍,內(nèi)存分配了用完之后是要釋放的悴侵,都是到malloc和calloc函數(shù)以及free函數(shù)。那么分配了內(nèi)存之后是不是真就free(pointer)這么簡單呢拭嫁?

 這里提及要注意的地方:參數(shù)pointer必須是調(diào)用malloc或calloc函數(shù)后返回的指針可免,而給free函數(shù)傳遞其它的值可能會造成死機或者結果是災難性的。
                       重點是指針的值做粤,而不是用來申請動態(tài)內(nèi)存的指針本身浇借。

可以看下代碼,

假如先前有void * p =malloc(sizeof(double)*6);

也有double * dp=(double )malloc(sizeof(double)6));

那么此刻如果free(dp)就會出現(xiàn)不可預知的錯誤怕品,free(p)是正確的逮刨,

若又p=dp,(或者p=(void *)dp),然后free(p)也是正確的

所謂災難性:無非就是釋放內(nèi)存中出現(xiàn)把不該釋放的東西給釋放了,然后引起了一些問題堵泽。

那么修己,怎么來驗證free(dp)就是錯誤的呢?這也許是個內(nèi)存泄露的問題迎罗,呵呵睬愤。

可以試下這樣一段代碼:

for(;;)

{

double * p=malloc(sizeof(double)*6);

free(p);

}

然后,看看你的內(nèi)存是否超支(不夠)了纹安?

正確的說法:

假如先前有double * p =malloc(sizeof(double)*6);

那么此刻如果free(p+1)就會出現(xiàn)不可預知的錯誤尤辱,free(p)是正確的,

原因是:分配內(nèi)存函數(shù)對該地址值及對應的內(nèi)存塊有記憶,而p+1不在記憶列表里厢岂,所以free(p+1)會引發(fā)災難性錯誤

可以試下這樣一段代碼:

for(;;)

{

double * p=malloc(sizeof(double)*6);

free(p+1);

}

再看看realloc函數(shù)光督,它可以用來重新分配經(jīng)m,c,r三者分配的內(nèi)存。那么重新分配真的是給一塊新的地址嘛塔粒?

  事實上并不是這樣的结借,r有兩個參數(shù),一個是指針卒茬,引用之前分配的內(nèi)存船老,重新分配的內(nèi)存是在原來基礎之上,大小則由第二個參數(shù)決定圃酵。
  也就是說柳畔,如果你家庭總收入6000元,總管(通常是母的)給兒子分配了1000元的零花錢郭赐,現(xiàn)在由于一些"不可抗力"因素薪韩,
  要重新分配money,那么,傳遞參數(shù)realloc(1000元的地址,newsize),newsize<=1000U。而本質(zhì)上是將兒子手中的money根據(jù)newsize抽走一部分俘陷,然后剩下的會做一些處理张惹。

動態(tài)內(nèi)存分配的一些原則:

1、需要時分配岭洲,用完就釋放,特別是堆上的(資源很有限)坎匿。

2盾剩、避免分配大量小塊內(nèi)存,因為堆上內(nèi)存的分配由于有系統(tǒng)開銷替蔬,所以分配許多的小內(nèi)存比分配幾塊大內(nèi)存開銷要大告私,而已不便于釋放和管理。

3承桥、編程的時候始終把用戶有限的內(nèi)存放在心上驻粟,分配了就要考慮在哪里釋放。

4凶异、循環(huán)中分配內(nèi)存一定要小心翼翼

5蜀撑、釋放內(nèi)存之前,確保不會無意中覆蓋堆上分配的內(nèi)存地址剩彬,否則會出現(xiàn)內(nèi)存泄露

//手動分配一塊內(nèi)存給學生酷麦,輸入學生的個人基本信息,并打印出來喉恋。

include <stdio.h>

include <malloc.h>

struct student
{
int num;
char *name;
char sex;
float score;
};
void main()
{
struct student *p=(struct student *)malloc(sizeof(struct student));
if(NULL==p)
{
printf("is wrong");
return ;
}
p->num=1;
p->name="xxx";
p->sex='m';
p->score=90;
printf("%d %s %c %.1f",p->num,p->name,p->sex,p->score);
}

//手動分配的內(nèi)存只能通過指向他的指針來訪問他沃饶,所以這個指針的值不要搞丟了

struct node
{
int data;
struct node *next;
};

struct node *head =(struct noode *)malloc(sizeof(struct node));

struct node *p =(struct noode *)malloc(sizeof(struct node));

head->next=p;

p->next=q;

q->next=NULL;

創(chuàng)建一個鏈表鏈接

include <stdio.h>

include <malloc.h>

struct node
{
int data;//數(shù)據(jù)域
struct node *next;//指針域
};

struct node * create()
{
int n,i;
printf("請輸入要創(chuàng)建鏈表的節(jié)點數(shù)");
scanf("%d",&n);
getchar();
//創(chuàng)建頭節(jié)點
struct node *head=(struct node *)malloc(sizeof(struct node));
//新建p節(jié)點,首節(jié)點
struct node *p =(struct node *)malloc(sizeof(struct node));
printf("請輸入數(shù)據(jù):");
scanf("%d",&p->data);
getchar();
//鏈接頭節(jié)點和首節(jié)點
head->next=p;
for(i=1;i<n;i++)
{
//新建q節(jié)點
struct node *q =(struct node *)malloc(sizeof(struct node));
printf("請輸入數(shù)據(jù):");
scanf("%d",&q->data);
getchar();
p->next=q;
p=q;
}
p->next=NULL;
return head;
}
void print(struct node *head)
{
struct node *p=head->next;
while(p)
{
printf("%d\n",p->data);
p=p->next;
}
}
//頭插
struct node * T_insert(struct node *head)
{
struct node *q =(struct node *)malloc(sizeof(struct node));
printf("input data:");
scanf("%d",&q->data);
getchar();
q->next=head->next;//先連接后面的節(jié)點轻黑,再連接前面的節(jié)點
head->next=q;
return head;
}

void main()
{
struct node *head;
head=create();
print(head);
head=T_insert(head);
print(head);
}

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末糊肤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子氓鄙,更是在濱河造成了極大的恐慌馆揉,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抖拦,死亡現(xiàn)場離奇詭異把介,居然都是意外死亡,警方通過查閱死者的電腦和手機蟋座,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門拗踢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人向臀,你說我怎么就攤上這事巢墅。” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我鳖目,道長移剪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任种樱,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘陡叠。我一直安慰自己,他們只是感情好肢执,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布枉阵。 她就那樣靜靜地躺著,像睡著了一般预茄。 火紅的嫁衣襯著肌膚如雪兴溜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天耻陕,我揣著相機與錄音拙徽,去河邊找鬼。 笑死诗宣,一個胖子當著我的面吹牛斋攀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播梧田,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼淳蔼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了裁眯?” 一聲冷哼從身側響起鹉梨,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎穿稳,沒想到半個月后存皂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡逢艘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年旦袋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片它改。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡疤孕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出央拖,到底是詐尸還是另有隱情祭阀,我是刑警寧澤鹉戚,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站专控,受9級特大地震影響抹凳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伦腐,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一赢底、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柏蘑,春花似錦幸冻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽信粮。三九已至黔攒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間强缘,已是汗流浹背督惰。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留旅掂,地道東北人赏胚。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像商虐,于是被迫代替她去往敵國和親觉阅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • C語言中內(nèi)存分配 在任何程序設計環(huán)境及語言中秘车,內(nèi)存管理都十分重要典勇。在目前的計算機系統(tǒng)或嵌入式系統(tǒng)中,內(nèi)存資源仍然是...
    一生信仰閱讀 1,148評論 0 2
  • (JG-2014-08-20)(前半部分經(jīng)過網(wǎng)上多篇文章對比整理)(后半部分根據(jù)ExceptionalCpp叮趴、C+...
    JasonGao閱讀 5,597評論 2 23
  • 前言:C語言是Java割笙、Objective-C、C++等高級語言的基礎眯亦、也是跨平臺開發(fā)的基礎伤溉,指針是C語言的重中之...
    androidjp閱讀 1,673評論 8 39
  • 多線程、特別是NSOperation 和 GCD 的內(nèi)部原理妻率。運行時機制的原理和運用場景乱顾。SDWebImage的原...
    LZM輪回閱讀 2,004評論 0 12
  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛閱讀 1,962評論 0 7