數組長度編譯期固定,無法應對運行時才知道大小的場景(如學生人數不定)。動態內存管理函數在堆區按需分配/釋放內存,實現動態數據結構(鏈表、樹、圖)。
| 函數 | 原型 | 功能 | 返回值 |
|---|---|---|---|
malloc | void *malloc(size_t size) | 分配 size 字節未初始化內存 | 成功返回首地址,失敗返回 NULL |
calloc | void *calloc(size_t n, size_t size) | 分配 n 個 size 字節塊,自動清零 | 同 malloc |
free | void free(void *ptr) | 釋放 ptr 指向的堆內存 | 無 |
// malloc
struct Student *p = (struct Student*)malloc(sizeof(struct Student));
if (!p) { perror("malloc"); exit(1); }
p->num = 101; ...
// calloc:分配數組並清零
struct Student *arr = (struct Student*)calloc(10, sizeof(struct Student));
// free:用完必須釋放
free(p);
p = NULL; // 防野指針
每個節點 = 數據域 + 指針域。
struct Node {
int num; // 數據域:學號
int age; // 數據域:年齡
struct Node *next; // 指針域:指向下一節點
};
next 指向同類型節點,形成遞歸結構。head 指向首節點;末節點 next = NULL。malloc 節點,串聯 next。p = head; while(p) { ... p = p->next; }。next 指向新節點,新節點 next 指向後繼。next 跳過目標節點,free 目標節點。create
#define NULL 0
#define TYPE struct Node
#define LEN sizeof(struct Node)
struct Node {
int num, age;
struct Node *next;
};
TYPE *create(int n) {
TYPE *head = NULL, *pf = NULL, *pb = NULL;
for (int i = 0; i < n; ++i) {
pb = (TYPE*)malloc(LEN);
printf("輸入學號 年齡: ");
scanf("%d%d", &pb->num, &pb->age);
if (i == 0) {
pf = head = pb; // 首節點
} else {
pf->next = pb; // 串聯
}
pb->next = NULL;
pf = pb; // pf 移至尾部
}
return head;
}
pf (previous front) 始終指向已建鏈表的尾節點。pb (previous back) 指向新分配節點。TYPE/LEN 簡化代碼,非必需。| 錯誤 | 後果 | 正確做法 |
|---|---|---|
| 不檢查 malloc 返回值 | NULL 解引用崩潰 | 必須 if(!p) handle_error(); |
| free 後不置 NULL | 野指針,二次 free、誤用 | free(p); p=NULL; |
| 重複 free | 堆損壞,不可預測崩潰 | free 後置 NULL,免疫重複 free |
| 釋放非 malloc 內存 | 未定義行為 | 只 free malloc/calloc/realloc 返回的指針 |
| 忘記 free(內存洩漏) | 長期運行耗盡內存 | 所有權清晰,配對 malloc/free |
| 柔性數組結構體 malloc 尺寸錯誤 | 越界訪問 | malloc(sizeof(Struct) + n*sizeof(Elem)) |
malloc/calloc 分配堆內存,free 釋放,三者配對使用。next),動態分配實現靈活增刪。pf->next = pb; pf = pb; 尾插法。