// 方案 A:直接指針
struct Node { int data; struct Node* next; };
struct Node* top; // 直接指向棧頂節點
// 方案 B:結構體包裹(教材常見)
struct LinkStack { struct Node* top; };
struct LinkStack s; // s.top 指向棧頂節點
| 維度 | 直接指針 (A) | 包裹結構體 (B) |
|---|---|---|
| 棧頂節點含義 | **同時是數據節點** | **純邏輯句柄**,不存數據 |
| 空棧表示 | top == NULL | s.top == NULL |
| 出棧操作 | 需特判:若出棧後為空,呼叫者的 top 變量需更新(傳二級指針或返回新指針) | 統一操作 s.top = s.top->next,句柄 s 地址不變,無需特判 |
| 多棧管理 | 每個棧一個全局指針變量,難封裝 | 每個棧一個 LinkStack 實例,易封裝為對象/模塊 |
| 傳參方式 | 函數需 struct Node** 修改頭指針 | 函數傳 struct LinkStack*,自然修改內部 top |
**抽象出「棧」這一數據結構實體**,將「頭指針」封裝在結構體中,使棧操作函數簽名統一(傳 LinkStack*),避免「頭指針本身是否為數據節點」的語義混淆,特別是**出棧導致頭指針變更**時,呼叫端無需關心指針變量更新細節。
typedef struct Node { int data; struct Node* next; } Node;
typedef struct { Node* top; } LinkStack;
void Push(LinkStack* s, int val) {
Node* p = malloc(sizeof(Node));
p->data = val; p->next = s->top; s->top = p;
}
int Pop(LinkStack* s, int* val) {
if (!s->top) return 0;
Node* p = s->top; *val = p->data;
s->top = p->next; free(p); return 1;
}
方案 B 體現了**抽象數據類型 (ADT)** 思想,工程實踐中強烈推薦。