一. 在c中分為這幾個存儲區:棧(stack),堆(heap),代碼段(text),數據段(data),bss 段,常量存儲區,
1.棧(stack):由編譯器自動分配釋放
自動分配,自動回收:棧區里面存放的是局部變量;在定義局部變量的時候,系統在棧區自動分配內存,在結束時,自動回收內存;
臟內存:棧區每次使用之前需要對棧區進行初始化;對於定義局部變量時,需要對局部變量進行初始化;
臨時性:(函數不能返回棧變量的指針,因為這個空間是臨時的)
反復使用:棧內存在程序中其實就是那一塊空間,程序反復使用這一塊空間。
棧的大小有限,因此 會出現棧溢出
2.堆(heap): 一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收
手動分配:malloc分配內存,free進行釋放內存;
臟內存:堆區每次使用之前呢需要對堆區進行初始化;
臨時性:堆區每次分配的內存釋放之后,就不能在使用;
malloc的使用:malloc每次分配的內存之后需要進行對其返回指針為void *類型,需要進行強制類型轉換,並對返回指針進行檢查是否為null;
malloc和free為c語言的標准庫函數,不能分配對象;
內存泄漏;
gcc中的malloc默認最小是以16B為分配單元的;如果malloc小於16B的大小時都會返 回一個16字節的大小的內存。
3.代碼段(text):
也叫文本段,代碼段其實就是函數編譯后生成的東西;
4.數據段(data):
也被稱為數據區、靜態數據區、靜態區;
c語言中
1.顯示初始化為非零全局變量,
2.顯示初始化為非零的靜態局部變量存儲在這個段;
5.bss 段(又叫:ZI(zero initial)段):.bss 段
c語言中
1).顯示初始化為0的全局變量;
2).未初始化的全局變量存儲在這個段。--零初始化段;
3).顯示初始化為0的static局部變量;
4).未初始化的static局部變量存儲在這個段;
6.自定義段:
段名由程序員自己定義,段的屬性和特征也由程序員自己定義。
7.常量存儲區:
一塊比較特殊的存儲區,存放的是常量,不允許修改(當然,你要通過非正當手段也可以修改)
8.文件映射區:
進程打開了文件后,將這個文件的內容從硬盤讀到進程的文件映射區,以后就直接在內存中操作這個 文件,讀寫完了后在保存時再將內存中的文件寫到硬盤中去。
9.內核映射區:
內核映射區就是將操作系統內核程序映射到這個區域了。
10.不同的存儲方式有不同的特點,簡單總結如下:
1)函數內部臨時使用,出了函數不會用到,就定義局部變量
2)堆內存和數據段幾乎擁有完全相同的屬性,大部分時候是可以完全替換的。
生命周期不一樣:
堆內存的生命周期是從malloc開始到free結束;
全局變量是從整個程序一開始執行就開始,直到整個程序結束才會消滅,伴隨程序運行的一生。
啟示:如果變量只是在程序的一個階段有用,用完就不用了,就適合用堆內存;
如果這個變量本身和程序是一生相伴的,那就適合用全局變量。
補充1:
1)所有未初始化的靜態(static)變量和全局變量,編譯器會默認賦初值0。
2)程序在加載到內存前,代碼區(text)和全局區(data和bss)的大小就是固定的,程序運行期間不能改變。
3)data段和bss區中的數據的生存周期為整個程序運行過程。
4)data段、text區和bss區是由編譯器在編譯時分配的,堆和棧是由系統在運行時分配的。
12.生命周期/作用域:
1).生命周期:指變量活着或者說是存在的時間;
2).作用域:指可以使用這個變量的范圍;
結合示例詳解:
#define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <stdio.h> #include <string.h>
int c = 1; //初始化為非零的全局變量:.data段
int a = 0; //初始化為0的全局變量:.bss段
char *p1; //未初始化的全局變量:.bss段
void main() { int b; //局部變量:stack(棧)
char s[] = "abc"; //局部變量:stack(棧)
char *p2; //局部變量:stack(棧)
char *p3 = "123456"; //字符串"123456"在常量區,p3局部變量:stack(棧)
static int c = 0; //顯示初始化的局部變量:.bss段
p1 = (char *)malloc(10); //malloc分配的內存:heap(堆)
strcpy(p1, "123456"); system("pause"); return; }
補充2:
明確區分堆與棧:
在bbs上,堆與棧的區分問題,似乎是一個永恆的話題,由此可見,初學者對此往往是混淆不清的,所以我決定拿他第一個開刀。
首先,我們舉一個例子:
void func() { int* p=new int[5]; //包含了堆與棧 }
new分配了一塊堆內存;
局部變量指針變量p分配的是一塊棧內存;
意義:在棧內存中存放了一個指向一塊堆內存的指針p。在程序會先確定在堆中分配內存的大小,然后調用operator new分配內存,然后返回這塊內存的首地址,放入棧中。