ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

C 语言通用自增长栈(Generic Self-growing Stack)源码级解析:基于 data_structures/stack 模块

C 语言通用自增长栈(Generic Self-growing Stack)源码级解析:基于 data_structures/stack 模块 示例工程【免费下载链接】CCollection of various algorithms in mathematics, machine learning, computer science, physics, etc implemented in C for educational purposes.项目地址https://gitcode.com/gh_mirrors/c/C点击查看免费下载本指南以仓库 data_structures/stack/README.md 为骨架深入讲解其中实现的模块化、泛型、自增长栈它通过void *指针数组容纳任意类型的数据容量不足时自动扩容并向调用方隐藏全部内部状态数据隐藏。读完本文你将掌握该栈的完整公共接口、底层实现机制扩容、偏移量、计数器、两种编译测试方式以及基于链表的对照实现可直接在自己的 C 项目中复用这套数据结构。模块概览一个文件即可引入data_structures/stack目录下包含以下组成部分文件作用stack.h公共接口头文件使用方只需#include stack.hstack.c基于动态数组的栈实现含自增长逻辑main.c面向数组栈的交互式测试框架程序stack_linked_list/另一种基于链表的栈实现含 stack.h、stack.c、main.c、Makefile如 README 所述使用方只需引入stack.h一个头文件即可获得全部能力头文件只暴露函数原型具体的内部数据结构指针数组、容量、计数器等全部隐藏在stack.c中体现了良好的封装与数据隐藏原则。公共接口五个核心函数README 定义的公共接口如下头文件 stack.h 中一一对应声明此外还额外声明了top()函数void initStack(); void push(void *object); void *pop(); int size(); int isEmpty();函数签名行为说明initStackvoid initStack()将栈初始化为容量为10 个元素的动态数组pushvoid push(void *object)将任意指针压入栈顶popvoid *pop()弹出并返回栈顶元素前置条件栈非空违反会触发断言sizeint size()返回当前栈内元素个数isEmptyint isEmpty()栈空返回1否则返回0由于栈元素类型为void *这套接口可以存放任何类型的指针整数、结构体、字符串等这正是泛型generic的含义。同时接口里还隐含了头文件中额外声明的 top()与pop()不同它只查看栈顶元素而不移除。源码级实现原理数据隐藏 自动扩容内部状态与初始化stack.c 通过文件级全局变量维护栈状态调用方完全不可见void **array; /* 指向实际存储元素的 void* 指针数组 */ int max 10; /* 当前容量 */ int counter 0;/* 元素计数器 */ int offset -1;/* 指向栈顶元素的偏移地址 */initStack()在 stack.c 中只做一件事——为max10个void *指针分配内存并用assert(array)确保分配成功void initStack() { array malloc(sizeof(void *) * max); assert(array); /* tests whether pointer is assigned to memory. */ }注意初始化后counter 0、offset -1表示栈为空、栈顶尚不存在任何元素。push 与自动扩容机制push()位于 stack.c是自增长特性的核心。其逻辑为先用assert(object)拒绝空指针入栈若counter max未满offset指向新栈顶*(array offset) object写入元素counter若栈已满调用内部工具函数grow()扩容然后递归调用自身完成入栈。扩容函数 grow() 不在公共接口中属于实现细节void grow() { max 10; /* 容量每次增加 10 */ void **tmp malloc(sizeof(void *) * max); for (i 0; i max - 10; i) /* 拷贝旧数组元素 */ *(tmp i) *(array i); free(array); /* 释放旧数组 */ array tmp; }从源码结构可以看到三个明确结论扩容步长固定为 10 个元素避免频繁调用malloc每次扩容都会重新分配整块内存并整体拷贝属于搬家式扩容与按需倍增的实现相比摊还开销略高但实现直观、便于教学理解push通过递归重试实现满则先扩容再入栈的闭环代码简洁。pop / size / isEmpty / toppop()位于 stack.cvoid *pop() { void *top *(array offset); assert(top); assert(!isEmpty()); /* 前置条件栈非空 */ offset--; counter--; return top; }它先断言栈非空与 README 中assumes: stack not empty的约定一致取出栈顶指针后下移offset、递减counter。注意它返回的是元素指针本身不释放元素内存——谁压入谁负责释放这是使用本栈时需要牢记的内存约定。其余函数实现极为精简stack.cint size() { return counter; } int isEmpty() { return counter 0; } void *top() { return array[offset]; }其中size()直接返回内部计数器isEmpty()等价于判断counter 0top()则按offset直接读取栈顶而不修改任何状态。编译与测试两种验证方式方式一链表栈带 Makefile可直接构建进入 stack_linked_list 目录按 Makefile 执行cd data_structures/stack/stack_linked_list make ./mainmain.c 依次压入 14 四个元素打印栈大小与内容再连续两次Stack_pop并打印可直观验证 LIFO后进先出行为Size: 4 Stack [Top --- Bottom]: 0x4 0x3 0x2 0x1 Stack after popping: Stack [Top --- Bottom]: 0x3 0x2 0x1 Stack after popping: Stack [Top --- Bottom]: 0x2 0x1方式二数组版交互式测试程序根目录下的 main.c 是一个交互式菜单程序提供 Push、Pop、Peek、Update、Display 五个操作可作为理解栈语义的参考测试框架gcc main.c -o stack_menu ./stack_menu运行后按菜单输入选择即可完成压栈、弹栈、查看栈顶、按位置更新元素以及从栈顶到栈底打印全部元素等操作选择0或按Ctrl-C退出。直接集成泛型栈到自有项目若要在自己的项目中复用 stack.c 与 stack.h只需gcc -c stack.c -o stack.o gcc your_main.c stack.o -o your_program并在your_main.c中#include stack.h随后依次调用initStack()→push()/pop()/top()即可。注意每个逻辑上独立的栈共用同一组全局状态如需多个互不干扰的栈实例更适合选用下方的链表实现。对照实现基于链表的栈stack_linked_listREADME 明确列出了第二种实现 stack_linked_list。其头文件 stack.h 采用经典的typedef 隐式指针风格封装句柄#define T Stack_T typedef struct T *T; /* 对外只暴露不透明句柄 */ extern T Stack_init(void); extern int Stack_size(T stack); extern int Stack_empty(T stack); extern void Stack_push(T stack, void *val); extern void *Stack_pop(T stack); extern void Stack_print(T stack);实现 stack.c 中每个节点为elem_t { void *val; struct elem *next; }栈结构体只维护count与head指针Stack_init分配栈句柄并置空Stack_push每次在表头插入新节点t-next stack-head; stack-head t;O(1)Stack_pop从表头摘除节点并free(t)返回保存的值Stack_print从栈顶向栈底打印各元素的指针值。与数组版相比链表版天然无容量上限、无需扩容逻辑且每个栈实例独立句柄封装但每个元素多一个指针节点的内存开销且需要显式Stack_init初始化句柄。两种实现恰好形成数组式自动扩容与链表式动态增长两种典型栈方案的对照。使用注意事项小结必须先initStack()再执行任何入栈/出栈操作否则array为未初始化指针pop()的前置条件是栈非空空栈弹栈会触发assert失败发布构建需自行移除断言或先检查isEmpty()push(NULL)会被断言拦截不可入栈空指针栈内保存的是指针本身栈退出/元素弹出后由调用方负责释放指向的动态内存数组版为全局单例状态适合单栈场景多栈并发或长期运行场景建议使用链表版句柄封装。综上所述data_structures/stack以极简的公共接口initStack/push/pop/size/isEmpty配合容量满 10 增 10的自增长机制为 C 语言学习者提供了一个兼顾封装性、泛型性与可读性的栈参考实现其相邻的链表版实现则展示了同一抽象在不同存储策略下的工程取舍。赞分享示例工程【免费下载链接】CCollection of various algorithms in mathematics, machine learning, computer science, physics, etc implemented in C for educational purposes.项目地址https://gitcode.com/gh_mirrors/c/C点击查看免费下载相关推荐解密Qwen3.6-27B-Fable-Fusion-711多阶段微调如何打造超越GPT-4的开源模型解密Qwen3.6 27B Fable Fusion 711多阶段微调如何打造超越GPT 4的开源模型 Qwen3.6 27B Fable Fusion 71人工智能大模型基础模型多模态Full Stack FastAPI Template基于 FastAPI 的生产级全栈项目模板指南Full Stack FastAPI Template基于 FastAPI 的生产级全栈项目模板指南 本指南介绍 FastAPI 官方推荐的 Full Sta后端Web框架API设计如何将PyTorch-NPU/deberta_base集成到生产环境终极部署指南与最佳实践如何将PyTorch NPU/deberta_base集成到生产环境终极部署指南与最佳实践 想要将先进的 DeBERTa 模型部署到生产环境这篇完整指南将带上一篇Instabot故事功能完全指南下载、上传和监控用户故事下一篇Git-it技术架构揭秘Electron框架下的Git教学工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表