// stack.h
#ifndef STACK_H
#define STACK_H
typedef int ElemType; // 可替換為 void* 實現泛型
typedef enum { OK = 0, ERROR = -1, OVERFLOW = -2 } Status;
typedef struct {
ElemType *base; // 棧底指針
ElemType *top; // 棧頂指針 (指向下一個可用位置)
int stackSize; // 當前分配容量
} SqStack;
/* 基礎操作 */
Status InitStack(SqStack *s); // 初始化
Status DestroyStack(SqStack *s); // 銷毀
Status ClearStack(SqStack *s); // 清空 (保留內存)
Status Push(SqStack *s, ElemType e); // 入棧 (自動擴容)
Status Pop(SqStack *s, ElemType *e); // 出棧
Status GetTop(SqStack *s, ElemType *e); // 取棧頂
int StackEmpty(SqStack *s); // 判空
int StackLength(SqStack *s); // 長度
#endif
#include "stack.h" #include#include #define INIT_CAPACITY 10 #define INCREMENT 10 Status InitStack(SqStack *s) { if (!s) return ERROR; s->base = malloc(INIT_CAPACITY * sizeof(ElemType)); if (!s->base) return OVERFLOW; s->top = s->base; s->stackSize = INIT_CAPACITY; return OK; } Status DestroyStack(SqStack *s) { if (!s) return ERROR; free(s->base); s->base = s->top = NULL; s->stackSize = 0; return OK; } Status ClearStack(SqStack *s) { if (!s) return ERROR; s->top = s->base; return OK; } Status Push(SqStack *s, ElemType e) { if (!s) return ERROR; // 滿則擴容 if (s->top - s->base >= s->stackSize) { int newSize = s->stackSize + INCREMENT; ElemType *newBase = realloc(s->base, newSize * sizeof(ElemType)); if (!newBase) return OVERFLOW; s->top = newBase + (s->top - s->base); // 修正 top 指針 s->base = newBase; s->stackSize = newSize; } *s->top++ = e; return OK; } Status Pop(SqStack *s, ElemType *e) { if (!s || !e) return ERROR; if (s->top == s->base) return ERROR; // 空棧 *e = *--s->top; return OK; } Status GetTop(SqStack *s, ElemType *e) { if (!s || !e) return ERROR; if (s->top == s->base) return ERROR; *e = *(s->top - 1); return OK; } int StackEmpty(SqStack *s) { return (s && s->top == s->base); } int StackLength(SqStack *s) { return (s ? s->top - s->base : -1); }
#include "stack.h" #includeint main() { SqStack s; InitStack(&s); // 壓入 1..100 測試擴容 for (int i = 1; i <= 100; ++i) { if (Push(&s, i) != OK) { fprintf(stderr, "Push failed at %d\n", i); return 1; } } printf("Stack length: %d, capacity: %d\n", StackLength(&s), s.stackSize); // 彈出驗證逆序 int val; for (int i = 100; i >= 1; --i) { Pop(&s, &val); if (val != i) { fprintf(stderr, "Mismatch: expected %d, got %d\n", i, val); return 1; } } printf("Pop test passed. Empty: %d\n", StackEmpty(&s)); DestroyStack(&s); return 0; }
| 決策點 | 方案 | 理由 |
|---|---|---|
| 頂指針語義 | top 指向下一個可用槽 (而非當前元素) | 入棧 *top++ = e,出棧 *--top,邏輯對稱、無 ±1 混淆 |
| 擴容策略 | 固定增量 +INCREMENT | 簡單、內存碎片小;大規模建議 *2 (均攤 O(1)) |
| realloc 後指針修正 | top = newBase + (oldTop - oldBase) | realloc 可能移動內存塊,必須按偏移量重算 top |
| 錯誤碼 | 枚舉 OK/ERROR/OVERFLOW | 區分邏輯錯誤(空棧彈出)與資源耗盡(OOM),調用者可差異化處理 |
| const 正確性 | GetTop/StackEmpty/StackLength 接受 const SqStack* | 未實現,建議加上,接口語義更精確 |
// gstack.h
typedef void *ElemType; // 存儲指針
typedef void (*FreeFunc)(void *); // 元素釋放器
typedef struct {
void **base;
void **top;
int stackSize;
FreeFunc free_elem; // 可選:銷毀時調用
} GSqStack;
Status GPush(GSqStack *s, void *e); // 傳入指針,所有權轉移
Status GPop(GSqStack *s, void **e); // 彈出指針,調用者負責釋放或繼續持有
配合 FreeFunc 實現 RAUI 風格:DestroyStack 遍歷調用 free_elem。
Push 未檢查擴容失敗 → 寫入野指針。realloc 後未修正 top → 指針失效。Pop 空棧不報錯直接返回 → 讀取未初始化內存。DestroyStack 未置 NULL → 重複釋放 / 野指針。NULL 指針參數。順序棧以連續內存、指針算術、動態擴容 實現 O(1) 均攤入棧/出棧。掌握頂指針語義、realloc 指針修正、錯誤碼設計、泛型化 void* 模式,即可構建生產級棧組件。進階方向:線程安全棧 (CAS/鎖)、持久化棧 (函數式數據結構)、硬件加速棧 (Intel MPX/CHERI)。