1. 作甚堆栈

堆 HEAP与栈 STACK 是两个不同观点,实在质上都是一种数据构造。

栈是一种按数据项排列的数据构造,只能在一端(栈顶 top)对数据项进行插入和删除,其符合后进先出(Last-In / First-Out)原则。
栈(os)一样平常是由编译器自动分配开释,其利用的是一级缓存。

堆也是一种分配办法类似于链表的数据构造,其可以在任意位置对数据项进行操作。
堆(os)一样平常由程序员手动分配开释,其利用的是二级缓存。

嵌入式里客栈事理及其纯C实现

在嵌入式天下里,堆栈一样平常指的仅是栈。

2. 浸染与意义

在 MCU 中,栈这种构造一样平常被 cpu 和 os 所利用。

在 cpu 裸机中利用情形分两种:一、主动进行函数调用时,STACK 用以暂存下一条指令地址、函数参数、函数中定义的局部变量;二、硬中断来临时,暂存当前实行的现场数据(下一条指令地址、各种缓存数据),中断结束后,用以规复。

在 os 中利用时,硬栈的利用同 cpu 裸机;但 os 一样平常会为每个任务额外分配一个软栈,在任务调度时,可用软中断打断当前正在实行的任务,栈则用以保存各自任务以规复。

3. 软硬之分

硬件堆栈:是通过寄存器 SP 作为索引指针的地址,是调用了 BL 等函数调用指令后硬件自动添补的堆栈。

软件堆栈:是编译器为了处理一些参数通报而做的堆栈,会由编译器自动产生和处理,可以通过相应的编译选项对其进行编辑。

大略一点说,硬件堆栈紧张做为地址堆栈用,而软件堆栈紧张会被分配成数据堆栈。
或看其栈顶指针是否和 CPU 具有分外的关联,有关联者(如 SP)“硬”,而无关联者“软”。

4. 栈的纯 C 实现

基本的抽象数据类型(ADT)是编写 C 程序必要的过程,这类 ADT 有链表、堆栈、行列步队和树等,本节紧张讲解下堆栈的几种实现方法以及他们的优缺陷。

堆栈(stack)的显著特点是后进先出(Last-In First-Out, LIFO),实在现的方法有三种可选方案:静态数组、动态分配的数组、动态分配的链式构造。

静态数组:特点是哀求构造的长度固定,而且长度在编译时候就得确定。
其优点是构造大略,实现起来方便而不随意马虎出错。
而缺陷便是不足灵巧以及固定长度不随意马虎掌握,适用于知道明确长度的场合。

动态数组:特点是长度可以在运行时候才确定以及可以变动原来数组的长度。
优点是灵巧,缺陷是由此会增加程序的繁芜性。

链式构造:特点是无长度上线,须要的时候再申请分配内存空间,可最大程度上实现灵巧性。
缺陷是链式构造的链接字段须要花费一定的内存,在链式构造中访问一个特定元素的效率不如数组。

首先先确定一个堆栈接口的头文件,里面包含了各个方案下的函数原型,放在一起是为了实现程序的模块化以及便于修正。
然后再接着分别先容各个方案的详细履行方法。

堆栈接口 stack.h 文件代码:

4.1 静态数组

在静态数组堆栈中,STACK_SIZE 表示堆栈所能存储的元素的最大值,用 top_element 作为数组下标来表示堆栈里面的元素,当 top_element == -1 的时候表示堆栈为空;当 top_element == STACK_SIZE - 1 的时候表示堆栈为满。
push 的时候 top_element 加 1,top_element == 0 时表示第一个堆栈元素;pop 的时候 top_element 减 1。

a_stack.c 源代码如下:

4.2 动态数组

头文件还是用 stack.h,改动的并不是很多,增加了 stack_size 变量取代 STACK_SIZE 来保存堆栈的长度,数组由一个指针来代替,在全局变量下缺省为 0。

create_stack 函数首先检讨堆栈是否已经创建,然后才分配所需数量的内存并检讨分配是否成功。
destroy_stack 函数首先检讨堆栈是否存在,已经开释内存之后把长度和指针变量重新设置为零。
is_empty 和 is_full 函数中添加了一条断言,防止任何堆栈函数在堆栈被创建之前就被调用。

d_stack.c 源代码如下:

4.3 链式构造

由于只有堆栈顶部元素才可以被访问,因此适用单链表可以很好实现链式堆栈,而且无长度限定。
把一个元素压入堆栈是通过在链表头部添加一个元素实现。
弹出一个元素是通过删除链表头部第一个元素实现。
由于没有长度限定,故不须要 create_stack 函数,须要 destroy_stack 进行开释内存以避免内存泄露。

l_stack.c 源代码如下: