【C语言入门】手把手教你实现顺序栈

栈是计算机科学中最基础且重要的数据结构之一,它遵循"后进先出"(LIFO)的原则。想象一下一叠盘子,你只能从最上面取放,这就是栈的直观体现。本文将用C语言带你一步步实现一个顺序栈,即使你是编程小白也能轻松理解!

什么是顺序栈?

顺序栈是使用数组实现的栈结构,具有以下特点:

  • 元素在内存中连续存储

  • 有一个指针(top)始终指向栈顶位置

  • 支持基本的入栈(push)和出栈(pop)操作

代码实现详解

1. 头文件定义(Stack.h)

首先我们需要定义栈的结构和声明相关操作函数:

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>// 定义栈中元素的数据类型
typedef int STDataType;// 栈的结构定义
typedef struct Stack
{STDataType* _a;    // 指向动态数组的指针int _top;          // 栈顶位置int _capacity;     // 当前容量
}Stack;// 函数声明
void StackInit(Stack* ps);                 // 初始化栈
void StackPush(Stack* ps, STDataType data);// 入栈
void StackPop(Stack* ps);                  // 出栈
STDataType StackTop(Stack* ps);            // 获取栈顶元素
int StackSize(Stack* ps);                  // 获取元素个数
int StackEmpty(Stack* ps);                 // 检查栈是否为空
void StackDestroy(Stack* ps);              // 销毁栈

2. 栈的实现(Stack.c)

初始化栈
void StackInit(Stack* ps) {assert(ps);  // 确保指针有效ps->_a = NULL;ps->_top = 0;      // 栈顶指向下一个空闲位置ps->_capacity = 0; // 初始容量为0
}

初始化时,我们将数组指针设为NULL,栈顶位置和容量都设为0。

入栈操作
void StackPush(Stack* ps, STDataType data) {assert(ps);// 检查栈是否已满,需要扩容if (ps->_capacity == ps->_top) {// 如果容量为0,初始分配4个元素空间,否则容量翻倍int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;// 重新分配内存STDataType* tmp = (STDataType*)realloc(ps->_a, sizeof(STDataType) * newcapacity);if (tmp == NULL) {perror("malloc error");return;}ps->_capacity = newcapacity;ps->_a = tmp;}// 将数据放入栈顶并更新栈顶位置ps->_a[ps->_top++] = data;
}

这里使用了动态内存分配,当栈满时自动扩容,这是实现可变大小栈的关键。

出栈操作
void StackPop(Stack* ps) {assert(ps);assert(ps->_top > 0); // 确保栈不为空ps->_top--; // 简单地将栈顶指针下移
}

出栈操作实际上只是移动栈顶指针,并不真正删除数据。

其他辅助函数
// 获取栈顶元素
STDataType StackTop(Stack* ps) {assert(ps);assert(ps->_top > 0); // 确保栈不为空return ps->_a[ps->_top - 1]; // 返回栈顶元素
}// 获取栈中元素个数
int StackSize(Stack* ps) {assert(ps);return ps->_top; // 栈顶位置就是元素个数
}// 检查栈是否为空
int StackEmpty(Stack* ps) {assert(ps);return ps->_top == 0; // 如果栈顶为0,栈为空
}// 销毁栈,释放内存
void StackDestroy(Stack* ps) {free(ps->_a);        // 释放数组内存ps->_a = NULL;       // 指针置空防止野指针ps->_top = 0;        // 重置栈顶ps->_capacity = 0;   // 重置容量
}

3. 测试代码(test.c)

#include "Stack.h"void TestStack(Stack* p) {// 测试初始化StackInit(p);// 测试入栈 - 添加6个元素StackPush(p, 1);StackPush(p, 2);StackPush(p, 3);StackPush(p, 4);StackPush(p, 5);StackPush(p, 6);// 测试栈是否为空且查看栈顶元素if (!StackEmpty(p))printf("栈顶元素: %d \n", StackTop(p));else printf("栈为空\n");// 测试出栈 - 弹出5个元素StackPop(p);StackPop(p);StackPop(p);StackPop(p);StackPop(p);// 测试栈元素个数printf("栈中元素个数: %d \n", StackSize(p));// 销毁栈StackDestroy(p);
}int main() {Stack p;TestStack(&p);return 0;
}

运行结果分析

运行测试代码,你会看到以下输出:

栈顶元素: 6
栈中元素个数: 1

这是因为我们依次压入了1-6六个数字,然后弹出了五个,最后只剩下一个元素。

关键点解析

  1. 动态扩容:当栈满时,我们通过realloc函数将容量翻倍,这是常见的扩容策略

  2. 栈顶指针_top指向的是下一个空闲位置,而不是当前栈顶元素的位置

  3. 断言使用:使用assert确保函数参数的有效性,提高代码健壮性

  4. 内存管理:记得在不再使用栈时调用StackDestroy释放内存,防止内存泄漏

常见问题

  1. Q: 为什么出栈操作不真正删除数据?
    A: 只需要移动栈顶指针,下次入栈时会覆盖该位置,提高效率

  2. Q: 初始容量为什么设为4?
    A: 这是一个经验值,太小会导致频繁扩容,太大浪费内存

  3. Q: 如何修改栈中存储的数据类型?
    A: 只需修改Stack.h中的STDataType定义即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/99182.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/99182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

北斗导航 | ARAIM(高级接收机自主完好性监测)算法在民航LPV-200进近中的具体实现流程

要详细说明ARAIM(高级接收机自主完好性监测)算法在民航LPV-200进近中的具体实现流程,需结合ARAIM的核心逻辑(多星座融合、多假设解分离、风险优化分配)与LPV-200的严格要求(垂直保护级VPL≤35米、垂直告警限VAL=35米、有效监测门限EMT≤15米等),以下是 step-by-step 的…

AIPex:AI + 自然语言驱动的浏览器自动化扩展

AIPex:AI + 自然语言驱动的浏览器自动化扩展 引言 一、快速上手 1.1 安装AIPex扩展 1.2 首次配置 1.3 界面介绍 第二章:30+工具详解 2.1 标签页管理工具集 🗂️ **get_all_tabs - 全局标签页概览** 🎯 **switch_to_tab - 智能标签页切换** 📋 **标签页批量操作** 📋 …

机器学习模型可信度与交叉验证:通俗讲解

先从一个故事说起&#xff1a;农场里的火鸡科学家&#xff0c;观察了一年发现“每天上午11点必有食物”&#xff0c;结果感恩节当天&#xff0c;它没等到食物&#xff0c;反而成了人类的食物。这个故事告诉我们&#xff1a;只靠过去的经验下结论&#xff0c;很可能出错——机器…

HTML5和CSS3新增的一些属性

1、HTML5新增特性这些新特性都有兼容性问题&#xff0c;基本是IE9以上版本浏览器才支持1&#xff09;新增语义化标签2&#xff09;新增多媒体标签音频&#xff1a;<audio>视频&#xff1a;<video>&#xff08;1&#xff09;视频<video>---尽量使用mp4格式<…

Redis的RedLock

RedLock算法深度解析RedLock是Redis作者针对分布式环境设计的多节点锁算法&#xff0c;核心目标是解决单点Redis在分布式锁场景中的可靠性缺陷。传统方案的局限性单节点Redis锁的问题单点故障&#xff1a;单个Redis实例宕机导致所有锁服务不可用可靠性不足&#xff1a;无法保证…

SpringMVC @RequestMapping的使用演示和细节 详解

目录 一、RequestMapping是什么&#xff1f; 二、RequestMapping 的使用演示 1.RequestMapping在方法上的使用&#xff1a; 2.RequestMapping同时在类和方法上使用&#xff1a; 3.RequestMapping指定请求参数&#xff1a; 4.RequestMapping使用Ant风格URL&#xff1a; 5.Requ…

flutter项目 -- 换logo、名称 、签名、打包

1、换logo, 透明底&#xff0c;下面5个尺寸&#xff0c;需要UI设计2、换名没配置型的改名方式如下 打开app/src/main/AndroidManifest.xml3、签名 运行 flutter doctor -vD:\project\Apk\keystore 自己建立的keystore文件夹&#xff0c; 注意命令后是 megoai-release-key(自…

【贪心算法】day9

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人的贪心算法学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码&#xff1b;&#xff…

linux C 语言开发 (八) 进程基础

文章的目的为了记录使用C语言进行linux 开发学习的经历。开发流程和要点有些记忆模糊&#xff0c;赶紧记录&#xff0c;防止忘记。 相关链接&#xff1a; linux C 语言开发 (一) Window下用gcc编译和gdb调试 linux C 语言开发 (二) VsCode远程开发 linux linux C 语言开发 (…

从零学算法1094

1094.拼车 车上最初有 capacity 个空座位。车 只能 向一个方向行驶&#xff08;也就是说&#xff0c;不允许掉头或改变方向&#xff09; 给定整数 capacity 和一个数组 trips , trips[i] [numPassengersi, fromi, toi] 表示第 i 次旅行有 numPassengersi 乘客&#xff0c;接他…

B2B企业营销型AI Agent服务商推荐:谁更专业?如何选型?

一、引言&#xff1a;为什么B2B企业需要营销型AI Agent&#xff1f;在当前竞争激烈的B2B市场中&#xff0c;企业普遍面临几大挑战&#xff1a;线索获取难&#xff1a;获客成本持续上升&#xff0c;高质量线索难以筛选。销售周期长&#xff1a;从初步接触到签单&#xff0c;往往…

算法-双指针5.6

目录 &#x1f33f;力扣611-有效三角形得个数 &#x1f9ca;题目链接&#xff1a;https://leetcode.cn/problems/valid-triangle-number/description/ &#x1f9ca;题目描述&#xff1a;​编辑 &#x1f9ca;解题思路&#xff1a; &#x1f9ca;解题代码&#xff1a; &a…

超参数自动化调优指南:Optuna vs. Ray Tune 对比评测

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;注册即送-H卡级别算力&#xff0c;80G大显存&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生更享专属优惠。 引言&#xff1a;从"手动炼丹"到"自动化…

软考-局域网基础考点总结

这篇文章用于整理软考网络相关的知识点&#xff0c;囊括了详细的局域网基础的考点&#xff0c;能够让你认真备考&#xff0c;基础知识一网打尽&#xff0c;让后续的学习更加通畅~ 第一部分&#xff1a;OSI七层参考模型 OSI(Open System Interconnection)模型是一个理论框架&am…

Node.js核心模块介绍

1. fs 模块fs&#xff08;File System&#xff09;模块允许对文件系统进行操作&#xff0c;提供了文件读写、文件夹操作等功能。fs 支持同步和异步两种 API。1.1. 常用方法读取文件&#xff1a;异步: fs.readFile()同步: fs.readFileSync()写入文件&#xff1a;异步: fs.writeF…

缓存三大劫攻防战:穿透、击穿、雪崩的Java实战防御体系(二)

第二部分&#xff1a;缓存击穿——热点key过期引发的“DB瞬间高压” 缓存击穿的本质是“某个热点key&#xff08;高并发访问&#xff09;突然过期”&#xff0c;导致大量请求在同一时间穿透缓存&#xff0c;集中冲击DB&#xff0c;形成“瞬间高压”。 案例3&#xff1a;电商秒杀…

Linux相关概念和易错知识点(45)(网络层、网段划分)

目录1.网络层&#xff08;1&#xff09;IP协议头格式&#xff08;2&#xff09;工作流程2.网段划分&#xff08;1&#xff09;五类地址&#xff08;2&#xff09;回环地址&#xff08;3&#xff09;网段的特殊地址&#xff08;4&#xff09;网络建设我们前面暂时跳过了网络层&a…

transition(过渡)和animation(动画)——CSS

1.transition过渡可以为一个元素在不同状态之间进行切换时添加过渡效果&#xff0c;实现不同状态间的变化效果。通过触发事件(鼠标悬停、点击等)&#xff0c;在两个状态间切换。1.1 使用语法&#xff1a;transition: [property] [duration] [timing-function] [delay];property…

Spring Cloud项目国产化改造MySQL迁移达梦数据库,SQL变更

达梦数据库下载地址&#xff1a;https://eco.dameng.com/download 达梦数据库安装文档&#xff1a;https://eco.dameng.com/document/dm/zh-cn/start/dm-install-linux.html 数据迁移SQLark工具使用 首先&#xff0c;本次MySQL迁移使用了SQLark工具 1.下载安装SQLark https…

Cesium---1.133版本不修改源码支持arcgis MapServer 4490切片

参照了这篇博文&#xff1a;https://blog.csdn.net/qq_19689967/article/details/121449888https://blog.csdn.net/qq_19689967/article/details/121449888 利用新版本的源码进行了修改&#xff0c;可以实现服务加载&#xff1a; Event.js import { Check,defined} from &qu…