C 記憶體分配
保留記憶體的過程稱為分配。分配記憶體的方式取決於記憶體的型別。
C 語言有兩種記憶體型別:靜態記憶體和動態記憶體。
靜態記憶體
靜態記憶體是在程式執行**前**為變數保留的記憶體。靜態記憶體分配也稱為*編譯時*記憶體分配。
當程式編譯時,C 語言會自動為每個變數分配記憶體。
例如,如果您建立一個包含 20 名學生(例如用於暑期學期)的整數陣列,C 語言將為 20 個元素保留空間,通常是 80 位元組的記憶體(20 * 4)。
但是當學期開始時,發現只有 12 名學生入學。那麼您就浪費了 8 個未使用元素的空間。
由於您無法更改陣列的大小,因此您將留下不必要的保留記憶體。
請注意,程式仍將執行,並且不會以任何方式損壞。但是,如果您的程式包含大量此類程式碼,它可能比最佳狀態執行得慢。
如果您希望更好地控制已分配的記憶體,請檢視下面的動態記憶體。
動態記憶體
動態記憶體是在程式開始執行**後**分配的記憶體。動態記憶體分配也可以稱為*執行時*記憶體分配。
與靜態記憶體不同,您可以完全控制在任何時候使用了多少記憶體。您可以編寫程式碼來確定您需要多少記憶體並進行分配。
動態記憶體不屬於變數,它只能透過指標訪問。
要分配動態記憶體,可以使用 malloc()
或 calloc()
函式。必須包含 <stdlib.h>
標頭檔案才能使用它們。malloc()
和 calloc()
函式分配一些記憶體並返回其地址的指標。
int *ptr1 = malloc(size);
int *ptr2 = calloc(amount, size);
malloc()
函式有一個引數,size,它指定要分配的記憶體量,以位元組為單位。
calloc()
函式有兩個引數
- amount - 指定要分配的專案數量
- size - 指定每個專案的大小,以位元組為單位
注意:malloc()
分配的記憶體中的資料是不可預測的。為避免意外值,請務必在讀取記憶體之前寫入一些內容。
與 malloc()
不同,calloc()
函式將零寫入所有已分配的記憶體。然而,這使得 calloc()
的效率略低。
為資料型別分配正確記憶體量的最佳方法是使用 sizeof
運算子
int *ptr1, *ptr2;
ptr1 = malloc(sizeof(*ptr1));
ptr2 = calloc(1, sizeof(*ptr2));
小心 sizeof(*ptr1)
告訴 C 語言測量地址處資料的大小。如果您忘記 *
而改為寫入 sizeof(ptr1)
,它將測量指標本身的大小,這通常是儲存記憶體地址所需的 8 個位元組。
注意:sizeof
運算子無法測量分配了多少動態記憶體。測量動態記憶體時,它只告訴您記憶體*資料型別*的大小。例如,如果您為 5 個 float
值保留空間,sizeof
運算子將返回 4,這是一個 float
值所需的位元組數。
讓我們使用動態記憶體來改進上面的學生示例。
如前所述,我們不能使用 sizeof
來測量分配了多少記憶體,我們必須透過將專案數量乘以資料型別的大小來計算。
示例
int *students;
int numStudents = 12;
students = calloc(numStudents, sizeof(*students));
printf("%d", numStudents * sizeof(*students)); // 48 位元組
自己動手試一試 »
注意
在使用動態記憶體分配時,您還應該**檢查錯誤**並在程式結束時**釋放記憶體**。您將在下一章中瞭解更多資訊。
棧記憶體
為了完整起見,值得一提的是棧記憶體。棧記憶體是一種動態記憶體,它為函式內部宣告的變數保留。在函式內部宣告的變數使用棧記憶體而不是靜態記憶體。
當函式被呼叫時,會為函式中的變數分配棧記憶體。當函式返回時,棧記憶體被釋放。
瞭解棧記憶體對於處理巢狀函式呼叫和遞迴的記憶體使用很有幫助。重複次數過多的遞迴可能會佔用過多的棧記憶體。當這種情況發生時,稱為**棧溢位**。