指针与栈:用指针模拟栈的入栈出栈操作
栈这种数据结构,说白了就是「后进先出」。你想想看,往一个桶里放盘子,最后放进去的总是最先被拿出来。我在嵌入式开发中,栈用得特别多——函数调用、中断现场保护、局部变量存储,底层全是栈在干活。
但今天咱们不聊硬件栈,而是用指针自己搭一个栈。为什么要这么做?因为理解了指针怎么操作栈,你才能真正明白内存是怎么被「管」起来的。
栈的基本结构
一个栈需要三个核心要素:
- 一块连续的内存区域——用来存数据
- 一个栈顶指针——指向当前栈顶位置
- 一个栈底指针——标记栈的起始位置
我个人习惯用数组来模拟这块内存,然后用一个指针变量来充当栈顶指针。这样既直观,又方便调试。
核心思路:栈顶指针永远指向下一个空闲位置(或者当前栈顶元素),入栈时指针上移,出栈时指针下移。
用指针实现入栈操作
入栈,就是把数据压到栈顶。用指针做这件事,其实就是:
- 检查栈是否已满
- 把数据写入栈顶指针指向的位置
- 栈顶指针向上移动
#include <stdio.h>
#include <stdbool.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int *top = stack; // 栈顶指针,初始指向栈底
bool push(int value) {
// 检查栈是否已满
if (top >= stack + STACK_SIZE) {
printf("栈已满,无法入栈\n");
return false;
}
*top = value; // 写入数据
top++; // 栈顶指针上移
return true;
}
这里有个细节:top++ 之后,top 指向的是下一个空闲位置,而不是当前元素。我在项目中遇到过这种设计带来的坑——如果你不小心把 top 当作当前元素来读,读到的就是未初始化的垃圾值。
我的习惯:入栈时先赋值再移动指针,出栈时先移动指针再取值。这样栈顶指针始终指向「下一个可用位置」,逻辑上更统一。
用指针实现出栈操作
出栈是入栈的逆过程:
- 检查栈是否为空
- 栈顶指针向下移动
- 取出栈顶指针指向的数据
int pop(void) {
// 检查栈是否为空
if (top == stack) {
printf("栈已空,无法出栈\n");
return -1; // 实际项目中建议用错误码或传参返回
}
top--; // 栈顶指针下移
return *top; // 取出数据
}
嗯,这里要注意:出栈时我们并没有真正「删除」数据,只是把栈顶指针往下挪了。下次入栈时,新数据会直接覆盖旧数据。这种做法在嵌入式系统中很常见——省时间、省指令。
完整示例:入栈出栈演示
int main() {
// 入栈测试
push(10);
push(20);
push(30);
// 出栈测试
printf("出栈: %d\n", pop()); // 30
printf("出栈: %d\n", pop()); // 20
printf("出栈: %d\n", pop()); // 10
return 0;
}
运行结果:
出栈: 30
出栈: 20
出栈: 10
你看,后入栈的 30 先出来,这就是栈的特性。
栈的常见状态检查
写栈代码时,我最怕的就是「栈溢出」和「空栈读取」。这两个问题在嵌入式环境里尤其致命——栈溢出可能直接覆盖掉其他变量,空栈读取则可能读到随机值。
所以,我建议你封装两个检查函数:
bool is_empty(void) {
return top == stack;
}
bool is_full(void) {
return top >= stack + STACK_SIZE;
}
有了这两个函数,入栈出栈时先做检查,代码就安全多了。
知识体系图
避坑指南
我曾经犯过的错:有一次在 STM32 上写栈操作,忘了检查栈是否为空。结果在中断服务函数里连续 pop 了两次,第二次读到了栈底之外的数据,直接导致系统跑飞。从那以后,我所有的栈操作都强制加检查——哪怕只是原型代码。
另外,用指针模拟栈时,指针的初始化和边界判断一定要做对。我见过不少新手把 top = &stack[0] 写成 top = stack,虽然效果一样,但后者更符合指针的语义——数组名本身就是首地址。
小结
用指针模拟栈,本质上就是控制一个指针在数组里上下移动。入栈时指针上移,出栈时指针下移。你只要记住三点:
- 栈顶指针的初始位置
- 入栈出栈时指针的移动方向
- 边界检查不能省
掌握了这些,你就能用指针轻松搭建一个栈。下次遇到需要后进先出的场景——比如撤销操作、表达式求值、函数调用模拟——你都可以用这套思路来解决。
一个小练习:试试把上面的代码改成「栈顶指针指向当前元素」的版本。你会发现入栈时要先移动指针再赋值,出栈时要先取值再移动指针。两种方式都能用,选一种你习惯的就好。
公众号:蓝海资料掘金营,微信deep3321