C 語言透過 <stdlib.h> 提供的 malloc()、calloc()、realloc()、free() 四大函數實現執行期記憶體管理。動態分配的記憶體位於堆區,生命週期由程式設計師手動控制,靈活性高但需嚴防記憶體洩漏與懸空指標。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
printf("請輸入陣列大小: ");
scanf("%d", &n);
// 1. 分配 n 個 int 的記憶體空間
int *p = (int *)malloc(n * sizeof(int));
if (p == NULL) {
fprintf(stderr, "記憶體分配失敗\n");
return 1;
}
// 2. 使用陣列
for (int i = 0; i < n; i++) {
p[i] = i * i; // 指標即陣列名,支援下標存取
}
for (int i = 0; i < n; i++) {
printf("%d ", p[i]);
}
putchar('\n');
// 3. 釋放記憶體(關鍵步驟!)
free(p);
p = NULL; // 防止懸空指標
return 0;
}
malloc 回傳 void*,C 語言可隱性轉換,C++ 需顯性轉型NULLmalloc 必須對應一個 freefree 後將指標設為 NULL,避免二次釋放或誤用#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int num;
char *name; // 動態字串需額外分配
char sex;
float score;
} Student;
int main(void) {
// 1. 分配結構體本身
Student *ps = (Student *)malloc(sizeof(Student));
if (ps == NULL) return 1;
// 2. 為字串成員分配記憶體
ps->name = (char *)malloc(20 * sizeof(char));
if (ps->name == NULL) {
free(ps);
return 1;
}
// 3. 賦值
ps->num = 102;
strcpy(ps->name, "Zhang Ping");
ps->sex = 'M';
ps->score = 62.5f;
// 4. 使用
printf("Number=%d\nName=%s\n", ps->num, ps->name);
printf("Sex=%c\nScore=%.1f\n", ps->sex, ps->score);
// 5. 逆序釋放:先釋放內嵌指標,再釋放結構體
free(ps->name);
free(ps);
ps = NULL;
return 0;
}
| 錯誤寫法 | 問題 | 正確做法 |
|---|---|---|
ps->name = "Zhang Ping"; | 指向字串常數區,不可修改,釋放時會崩潰 | 分配記憶體後用 strcpy 複製 |
只 free(ps) | 內嵌 name 記憶體洩漏 | 先 free(ps->name) 再 free(ps) |
未檢查 malloc 回傳值 | 分配失敗時解參考導致崩潰 | 永遠檢查 NULL |
int **matrix = (int **)malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
matrix[i] = (int *)malloc(cols * sizeof(int));
}
// 釋放時逐行 free,最後 free(matrix)
int *matrix = (int *)malloc(rows * cols * sizeof(int)); // 存取:matrix[i * cols + j] free(matrix); // 一次釋放
typedef struct {
int len;
int data[]; // 不定長陣列,必須是結構體最後一個成員
} FlexArray;
FlexArray *arr = malloc(sizeof(FlexArray) + n * sizeof(int));
arr->len = n;
// 釋放:free(arr) 一次搞定
MALLOC_CHECK_ 環境變數偵測p = NULL 後再次解參考會立即崩潰(好事),便於定位動態記憶體管理是 C 語言核心能力。遵循「誰分配誰釋放、分配即檢查、釋放即歸零」三原則,善用工具輔助除錯,即可安全發揮堆區記憶體的最大靈活性。