程式設計師們經常編寫記憶體管理程式,往往提心吊膽。如果不想觸雷,唯一的解決辦法就是發現所有潛伏的地雷並且排除它們,躲是躲不了的。本文的內容比一般教科書的要深入得多,讀者需細心閱讀,做到真正地通曉記憶體管理。
1、記憶體分配方式
記憶體分配方式有三種:
(1)從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在。例如全域性變數,static變數。
(2)在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。
(3) 從堆上分配,亦稱動態記憶體分配。程式在執行的時候用malloc或new申請任意多少的記憶體,程式設計師自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由我們決定,使用非常靈活,但問題也最多。
補充:乙個由c/c++編譯的程式占用的記憶體分為以下幾個部分
1、棧區(stack)- 由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。其
操作方式類似於資料結構中的棧。
2、堆區(heap) - 一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可能由os回
收 。注意它與資料結構中的堆是兩回事,分配方式倒是類似於鍊錶,呵呵。
3、全域性區(靜態區)(static)-,全域性變數和靜態變數的儲存是放在一塊的,初始化的
全域性變數和靜態變數在一塊區域, 未初始化的全域性變數和未初始化的靜態變數在相鄰的另
一塊區域。 - 程式結束後由系統釋放。
4、文字常量區 -常量字串就是放在這裡的。 程式結束後由系統釋放
5、程式**區-存放函式體的二進位制**。
2、常見的記憶體錯誤及其對策
c++/c程式中,指標和陣列在不少地方可以相互替換著用,讓人產生一種錯覺,以為兩者是等價的。
陣列要麼在靜態儲存區被建立(如全域性陣列),要麼在棧上被建立。陣列名對應著(而不是指向)一塊記憶體,其位址與容量在生命期內保持不變,只有陣列的內容可以改變。
指標可以隨時指向任意型別的記憶體塊,它的特徵是「可變」,所以我們常用指標來操作動態記憶體。指標遠比陣列靈活,但也更危險。
下面以字串為例比較指標與陣列的特性。
3.1 修改內容
示例3-1中,字元陣列a的容量是6個字元,其內容為hello。a的內容可以改變,如a[0]= 『x』。指標p指向常量字串「world」(位於靜態儲存區,內容為world),常量字串的內容是不可以被修改的。從語法上看,編譯器並不覺得語句 p[0]= 『x』有什麼不妥,但是該語句企圖修改常量字串的內容而導致執行錯誤。
char a = 「hello」;
a[0] = 『x』;
cout << a << endl;
char *p = 「world」; // 注意p指向常量字串
p[0] = 『x』; // 編譯器不能發現該錯誤
cout << p << endl;
示例3.1 修改陣列和指標的內容
3.2 內容複製與比較
不能對陣列名進行直接複製與比較。示例7-3-2中,若想把陣列a的內容複製給陣列b,不能用語句 b = a ,否則將產生編譯錯誤。應該用標準庫函式strcpy進行複製。同理,比較b和a的內容是否相同,不能用if(b==a) 來判斷,應該用標準庫函式strcmp進行比較。
語句p = a 並不能把a的內容複製指標p,而是把a的位址賦給了p。要想複製a的內容,可以先用庫函式malloc為p申請一塊容量為strlen(a)+1個字元的 記憶體,再用strcpy進行字串複製。同理,語句if(p==a) 比較的不是內容而是位址,應該用庫函式strcmp來比較。
// 陣列…
char a = "hello";
char b[10];
strcpy(b, a); // 不能用 b = a;
if(strcmp(b, a) == 0) // 不能用 if (b == a)
…// 指標…
int len = strlen(a);
char *p = (char *)malloc(sizeof(char)*(len+1));
strcpy(p,a); // 不要用 p = a;
if(strcmp(p, a) == 0) // 不要用 if (p == a)…
示例3.2 陣列和指標的內容複製與比較
3.3 計算記憶體容量
用運算子sizeof可以計算出陣列的容量(位元組數)。示例7-3-3(a)中,sizeof(a)的值是12(注意別忘了』』)。指標p指向a,但是 sizeof(p)的值卻是4。這是因為sizeof(p)得到的是乙個指標變數的位元組數,相當於sizeof(char*),而不是p所指的記憶體容量。 c++/c語言沒有辦法知道指標所指的記憶體容量,除非在申請記憶體時記住它。
注意當陣列作為函式的引數進行傳遞時,該陣列自動退化為同型別的指標。示例7-3-3(b)中,不論陣列a的容量是多少,sizeof(a)始終等於sizeof(char *)。
char a = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12位元組
cout<< sizeof(p) << endl; // 4位元組
示例3.3(a) 計算陣列和指標的記憶體容量
void func(char a[100])
示例3.3(b) 陣列退化為指標
C 記憶體管理詳解
偉大的bill gates 曾經失言 640k ought to be enough for everybody bill gates 1981 程式設計師們經常編寫記憶體管理程式,往往提心吊膽。如果不想觸雷,唯一的解決辦法就是發現所有潛伏的地雷並且排除它們,躲是躲不了的。本文的內容比一般教科書的要...
C 記憶體管理詳解
踏入c 中的雷區 c 記憶體管理詳解 這篇文章回答了我之前的乙個問題,就是分配記憶體用malloc好,還是用new好,今天跑程式的時候,發現malloc老是失敗,氣得不行,最後看到了這篇文章,原來如此,以後堅決用new了。1 有了malloc free為什麼還要new delete?malloc與f...
C記憶體管理詳解
規則1 用malloc或new申請記憶體之後,應該立即檢查指標值是否為null。防止使用指標值為null的記憶體。規則2 不要忘記為陣列和動態記憶體賦初值。防止將未被初始化的記憶體作為右值使用。規則3 避免陣列或指標的下標越界,特別要當心發生 多1 或者 少1 操作。規則4 動態記憶體的申請與釋放必...