12.03 Implementing Array-Based Stacks for Deterministic Execution
Executive Summary: Implementing a bounded array stack. We explore top index manipulation, push/pop mechanics, and deterministic execution.
💻 1. Annotated Source Code
#ifndef STACK_H #define STACK_H class Stack { public: virtual void push(int newEntry) = 0; virtual int pop() = 0; virtual int peek() const = 0; virtual bool isEmpty() const = 0; virtual void makeEmpty() = 0; }; #endif
#ifndef ARRAY_STACK_H #define ARRAY_STACK_H #include "Stack.h" #include <iostream> using namespace std; class ArrayStack : public Stack { public: ArrayStack(int s = 16) : MAX_SIZE(s) { top = -1; mArray = new int[MAX_SIZE]; }//end ctor void push(int newEntry) override { if (top < MAX_SIZE - 1) { top++; mArray[top] = newEntry; } else { cout << "Error: Stack is full! Cannot push." << endl; } }//end push int pop() override { if (!isEmpty()) { return mArray[top--]; } else { cout<<"You can't pop from an empty stack!"<<endl; return 0; } }//end pop int peek() const override { if (!isEmpty()) { return mArray[top]; } else { cout << "The stack is empty." << endl; return 0; } }//end peek bool isEmpty() const override { return top == -1; }//end isEmpty void makeEmpty() override { top = -1; } private: int* mArray; const int MAX_SIZE; int top; }; #endif
#include <iostream> #include "ArrayStack.h" using namespace std; int main() { ArrayStack stack; ArrayStack stack2; for (int i = 0; i < 17; i++) { stack.push(i); } while (!stack.isEmpty()) { stack2.push(stack.pop()); } cout << "Same order as entered, using second stack:" << endl; while (!stack2.isEmpty()) { cout << stack2.pop() << endl; } return 0; }
📐 2. Architecture & UML Class Model
<<interface>>
Stack<T>
Stack Interface Contract
Attributes / Data Members
(none / stateless)
Operations / Methods
+push(entry: const T&) : bool[pure virtual =0]
+pop() : bool[pure virtual =0]
+peek() : T const[pure virtual =0]
+isEmpty() : bool const[pure virtual =0]
+~Stack()[virtual]
<<template class>>
ArrayStack<T>
LIFO Array Stack
Attributes / Data Members
-items[CAPACITY] : T
-top : int32_t = -1
+MAX_STACK : constexpr size_t = 10
Operations / Methods
+ArrayStack()
+push(newEntry: const T&) : bool[override, O(1)]
+pop() : bool[override, O(1)]
+peek() : T const[override, O(1)]
+isEmpty() : bool const[override, O(1)]
🔗 Architectural Relationships & Hierarchy
ArrayStack<T>
- - ▷
implements interface
- - ▷
Stack<T>
📚 3. Core C++ Concepts Deep-Dive
Stack Operations
Push and pop operate on the top index in $O(1)$ time.
🥞 LIFO Stack Memory Layout (Push / Pop)
⚡ 4. Embedded Systems & Hardware Reality
Deterministic LIFO Buffering
Array-backed stacks have bounded memory and execute in guaranteed single-cycle operations.
💡 5. Production-Ready Embedded Refactoring
💡 Production-Ready Refactor
template <typename T, size_t Cap> class SafeArrayStack { std::array<T, Cap> data_; size_t top_ = 0; };
📝 Knowledge Verification Quiz
Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.
Q1. Why is an ArrayStack preferred over a LinkedStack in embedded systems?
Detailed Explanation:
Array stacks avoid heap fragmentation and node pointer overhead while maximizing CPU cache performance.