C 语言手动实现栈结构:入栈与出栈详解
栈(Stack)是线性表中一种重要的数据结构,遵循'后进先出'(LIFO)原则。在实际开发中,有时我们需要脱离标准库,手动构建一个轻量级的栈结构来适应特定需求。下面分享一个经典的 C 语言版本实现,采用单链表作为底层存储,重点展示指针操作与内存管理。
头文件设计
首先定义栈的结构体及接口声明。这里使用 struct stack 包含数据域和指向下一个节点的指针。
#ifndef _1_H
#define _1_H
#ifdef __cplusplus
extern "C" {
#endif
#define TRUE 1
#define FALSE 0
// 结构体定义
typedef struct stack
{
int score;
struct stack *next;
}STACK;
STACK *initStack(STACK *t);
int EMPTY(STACK *t);
STACK *PUSH(STACK *t,int x);
STACK *POP(STACK *t,int *x);
#ifdef __cplusplus
}
#endif
核心实现逻辑
接下来看具体的函数实现。初始化时只需将头指针置空;判空则检查头指针是否为 NULL。
#include <stdio.h>
#include <stdlib.h>
#include "1.h"
STACK *initStack(STACK *t)
{
t = NULL;
return t;
}
int EMPTY(STACK *t)
{
return ((NULL == t) ? TRUE : FALSE);
}
入栈操作(PUSH)需要动态分配内存。注意检查 malloc 是否成功,防止内存不足导致程序崩溃。新节点插入头部,并更新头指针。
STACK *PUSH(STACK *t,int x)
{
STACK *p;
p = (STACK *)malloc(sizeof(STACK));
if(NULL == p)
{
printf("memory error\n");
return NULL;
}
p->score = x;
p->next = t;
return p;
}
出栈操作(POP)相对复杂些。需要先保存当前头节点,读取数据,然后移动头指针,最后释放旧节点内存。这里有个细节:函数返回新的头指针,调用者必须接收这个返回值才能正确维护栈顶状态。
STACK *POP(STACK *t,int *x)
{
STACK *p;
if(NULL == t)
{
printf("underflow\n");
return NULL;
}
else
{
*x = t->score;
p = t;
t = t->next;
free(p);
return t;
}
}
测试验证
最后在主函数中模拟压入一组数据,再依次弹出,观察顺序是否符合预期。
int main()
{
int a[]={50,80,70,90},b[4]={0};
int i,score,flag;
STACK *top;
top = initStack(top);
flag = EMPTY(top);
printf("-----------------------------\n");
printf("this stack's empty flag is %d\n",flag);
printf("-----------------------------\n");
printf("PUSH:\n");
for(i =0;i < 4;i++)
{
printf("%d\n",a[i]);
top = PUSH(top, a[i]);
}
flag = EMPTY(top);
printf("-----------------------------\n");
printf("this stack's empty flag is %d\n",flag);
printf("-----------------------------\n");
printf("POP:\n");
for(i =0;i < 4;i++)
{
top = POP(top, &b[i]);
printf("%d\n",b[i]);
}
flag = EMPTY(top);
printf("-----------------------------\n");
printf("this stack's empty flag is %d\n",flag);
printf("-----------------------------\n");
top =NULL;
return 0;
}
总结
这段代码虽然简单,但涵盖了栈操作的核心要点。实际使用时,建议增加错误处理机制,比如更详细的日志或异常抛出。另外,确保每次 malloc 都有对应的 free,避免内存泄漏。对于初学者来说,理解指针在函数间的传递与返回是掌握此类实现的关键。
