在《C語言實現單鏈表的基本操作》中已實現單鏈表清空。本文將場景遷移至雙向非循環鏈表(無頭結點),核心思路一致:從頭節點遍歷,逐個釋放節點內存,最終將頭指針置 NULL。關鍵差異在於雙向鏈表需同時維護 prior 與 next 兩個指針域,釋放順序需謹慎設計以避免野指針訪問。
typedef struct Node {
int element;
struct Node* prior;
struct Node* next;
} Node;
Node* ClearDoubleLinkedList(Node* pHead) {
if (!pHead) {
printf("%s: 原鏈表為空,無需清空\n", __FUNCTION__);
return NULL;
}
Node* pCurr = pHead;
while (pCurr->next) { // 只要有後續節點
pCurr = pCurr->next; // 先移動到下一個節點
free(pCurr->prior); // 釋放前一個節點(原當前節點)
pCurr->prior = NULL; // 斷開反向指針,防野指針
}
free(pCurr); // 釋放最後一個節點
pCurr = NULL;
printf("%s: 雙向非循環鏈表清空成功\n", __FUNCTION__);
return NULL; // 返回空頭指針
}
初始: HEAD <-> A <-> B <-> C -> NULL 步驟1: HEAD已釋放 pCurr指向A 釋放HEAD(無) 略過 步驟2: pCurr=A -> next=B 釋放A.prior(HEAD) A.prior=NULL 步驟3: pCurr=B -> next=C 釋放B.prior(A) B.prior=NULL 步驟4: pCurr=C -> next=NULL 釋放C.prior(B) C.prior=NULL 循環結束: 釋放C 返回NULL
pCurr = pCurr->next 保存下一節點地址,再 free(pCurr->prior) 釋放前一節點,避免釋放後訪問野指針。pCurr->prior = NULL 非必須但推薦,防止釋放內存被誤用。pCurr->next 導致最後一個節點不進循環體,需循環後單獨 free(pCurr)。#include#include #include typedef struct Node { int element; struct Node* prior; struct Node* next; } Node; Node* CreateList(); // 尾插法建表(輸入正整數,負數結束) void PrintList(Node* head); // 正向打印 Node* ClearDoubleLinkedList(Node* head); int main() { Node* list = CreateList(); // 輸入:10 20 30 -1 PrintList(list); // 10 20 30 list = ClearDoubleLinkedList(list); PrintList(list); // (空輸出) return 0; }
雙向鏈表清空操作雖然邏輯簡單,但指針操作順序稍有不慎即導致崩潰或內存洩漏。掌握「先推進、後釋放、再斷鏈」的標準模式,是 C 語言指針功力的基本功體現。