必须用++top压栈、top--弹栈,因++top先增后存确保写入正确位置,top--先取后减保证读取栈顶元素;边界检查必须手动显式进行,否则必然越界。
前置自增(++top)用于压栈,后置自减(top--)用于弹栈,但必须配手动边界检查,否则必然越界。
为什么必须用 ++top 而不是 top++ 压栈
压栈的本质是“先腾出位置,再放数据”。假设
初始为 -1(空栈),数组
从索引 0 开始增长:
:先将
变成 0,再写入
,语义清晰
:先用
写入
—— 直接越界,未定义行为
即使
初始为 0,
也会导致写入旧位置,跳过当前空闲槽位
为什么弹栈必须用 top-- 而不是 --top
弹栈要“先读值,再释放位置”。栈顶元素在
,读完才应把
下移:
:取
(假设当前
),再令
变为 1
:先令
变成 1,再取
—— 返回了错误的元素,且原栈顶丢失
链栈中同理:
等价于后置逻辑
边界检查不能依赖运算符,必须显式判断
和
运算符本身不感知数组长度或空状态,越界完全由程序员负责拦截:
压栈前检查:
弹栈前检查:
若用指针实现(如
中
指向元素地址),检查应为:
(空栈)或
(满栈)
忽略任一检查,轻则数据错乱,重则段错误或覆盖相邻变量
数组栈与链栈在自增/自减使用上的差异
数组栈直接操作整型
索引,而链栈操作的是指针
,但前置/后置逻辑一致:
数组栈压栈:
链栈压栈:
(这里没有自增,但等效于“先连后设”)
数组栈弹栈:
链栈弹栈:
(等效于后置取值+移动)
关键点:无论哪种实现,**“取值发生在指针移动之前”这一顺序不可颠倒**
最容易被忽略的是:自增自减只是语法糖,它不改变栈的逻辑约束;所有安全边界都得靠人写出来,编译器不会帮你加
。
topstack[SIZE]stack[++top] = xtopstack[0]stack[top++] = xtop == -1stack[-1]toptop++stack[top]topreturn stack[top--]stack[2]top == 2topreturn stack[--top]topstack[1]temp = s->top; s->top = s->top->next; return temp->data;++--if (top >= SIZE - 1) { /* 栈满 */ return; }if (top == -1) { /* 栈空 */ return -1; }SqStacktopif (S->top == S->base)if (S->top - S->base >= S->stacksize)toptopstack[++top] = x;newNode->next = s->top; s->top = newNode;return stack[top--];temp = s->top; s->top = s->top->next; return temp->data;if