struct ListEntry {
int number; // 數據域
struct ListEntry *next; // 指針域,指向下一節點
};
#include <stdio.h>
#include <stdlib.h>
struct ListEntry {
int number;
struct ListEntry *next;
};
int main() {
struct ListEntry start = {0, NULL}; // 頭節點 (哨兵)
struct ListEntry *node = &start; // 工作指針指向頭節點
// 1. 動態建立鏈表:尾插法
for(int i = 1; i <= 10; i++) {
node->next = (struct ListEntry*)malloc(sizeof(struct ListEntry));
if(!node->next) {
fprintf(stderr, "記憶體分配失敗\n");
return 1;
}
node = node->next; // 移動到新節點
node->number = i; // 填充數據
node->next = NULL; // 終止標記
}
// 2. 遍歷輸出
printf("鏈表內容: ");
node = start.next; // 跳過頭節點
while(node) {
printf("%d ", node->number);
node = node->next;
}
printf("\n");
// 3. 釋放記憶體 (重要!)
node = start.next;
while(node) {
struct ListEntry *tmp = node;
node = node->next;
free(tmp);
}
start.next = NULL;
return 0;
}
記憶體佈局: start (棧上) 堆上節點 1 堆上節點 2 ... 堆上節點 10 +------+------+ +------+------+ +------+------+ +------+------+ | num=0| next |----->| num=1| next |----->| num=2| next |-----> ... ->| num=10|NULL| +------+------+ +------+------+ +------+------+ +------+------+ 頭節點(哨兵) 數據節點 數據節點 尾節點
Node *tail = head;
for(...) {
tail->next = new_node();
tail = tail->next;
}
for(...) {
new_node->next = head->next;
head->next = new_node;
}
for(Node *p = head->next; p; p = p->next) {
// 訪問 p->data
}
Node *p = head->next;
while(p) {
Node *tmp = p;
p = p->next;
free(tmp);
}
head->next = NULL;
| 錯誤代碼 | 問題 | 修正 |
|---|---|---|
node = malloc(...); node->next = ... | 先移動指標再分配,導致頭節點丟失 | 先 node->next = malloc(...) 再 node = node->next |
未檢查 malloc 回傳值 | 分配失敗導致空指標解引用 | 必須檢查 if(!ptr) handle_error() |
釋放時 free(node); node = node->next; | 釋放後訪問野指標 | 先保存 next 再 free |
未設置 next = NULL | 尾節點指向隨機地址 | 新節點必須初始化 next = NULL |
prev 指標,支援反向遍歷、O(1) 刪除next 指向頭節點,適用循環調度鏈表是動態資料結構的基石。「頭節點哨兵 + 尾插建立 + 遍歷訪問 + 正確釋放」是 C 語言鏈表操作的標準範式。掌握指標操作、記憶體管理、邊界條件處理,是從數組思維轉向指標思維的關鍵一步。