Project 12.03 Section 12 ⚡ Embedded Relevance: High ArrayStack LIFO Bounded Memory Deterministic

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

📐 ArrayStack LIFO Fixed Memory Architecture
+ Public - Private # Protected
<<interface>> Stack<T> Stack Interface Contract
(none / stateless)
+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
-items[CAPACITY] : T
-top : int32_t = -1
+MAX_STACK : constexpr size_t = 10
+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)

data[0] (Bottom) data[1] data[top-1] (Top Element) Free Space (Capacity) top_ index

⚡ 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?
A It uses contiguous memory, requires zero per-node heap allocations, and exhibits superior cache locality.
B It can store infinite items.
C It is non-deterministic.
D It disables interrupts.
Detailed Explanation: Array stacks avoid heap fragmentation and node pointer overhead while maximizing CPU cache performance.