Implementing Stack and Queue with Fixed-Size Arrays in C, C#, and C++

Stacks and queue are foundational linear data structures governed by LIFO and FIFO principles, respectively. This article demonstrates how to implement both using static arrays in C, C#, and C++—with redesigned logic, renamed identifiers, and structural variations while preserving correctness and clarity.

Array-Based Stack Implementation

A stack maintains a single index (head) trakcing the next available slot. All operations run in O(1) time.

Core Operations

  • Iniitalize: Set head to 0 (empty state).
  • Push: Store value at data[head], then increment head.
  • Pop: Decrement head, then return data[head].
  • Peek: Return data[head - 1] if non-empty.
  • IsEmpty: head == 0.
  • IsFull: head == capacity.

C Version

#include <stdio.h>
#include <stdbool.h>

#define STACK_CAPACITY 100

typedef struct {
    int elements[STACK_CAPACITY];
    size_t head;
} ArrayStack;

void stack_init(ArrayStack* s) { s->head = 0; }

bool stack_is_empty(const ArrayStack* s) { return s->head == 0; }

bool stack_is_full(const ArrayStack* s) { return s->head == STACK_CAPACITY; }

void stack_push(ArrayStack* s, int item) {
    if (stack_is_full(s)) {
        fprintf(stderr, "Error: stack overflow\n");
        return;
    }
    s->elements[s->head++] = item;
}

int stack_pop(ArrayStack* s) {
    if (stack_is_empty(s)) {
        fprintf(stderr, "Error: stack underflow\n");
        return -1;
    }
    return s->elements[--s->head];
}

int stack_peek(const ArrayStack* s) {
    if (stack_is_empty(s)) {
        fprintf(stderr, "Error: cannot peek empty stack\n");
        return -1;
    }
    return s->elements[s->head - 1];
}

int main() {
    ArrayStack st;
    stack_init(&st);
    stack_push(&st, 42);
    stack_push(&st, 99);
    printf("Top: %d\n", stack_peek(&st));
    printf("Popped: %d\n", stack_pop(&st));
    return 0;
}

C# Version

using System;

class ArrayStack {
    private readonly int[] _storage;
    private int _size;

    public ArrayStack(int capacity) {
        _storage = new int[capacity];
        _size = 0;
    }

    public bool IsEmpty => _size == 0;
    public bool IsFull => _size == _storage.Length;

    public void Push(int value) {
        if (IsFull) throw new InvalidOperationException("Stack overflow");
        _storage[_size++] = value;
    }

    public int Pop() {
        if (IsEmpty) throw new InvalidOperationException("Stack underflow");
        return _storage[--_size];
    }

    public int Peek() {
        if (IsEmpty) throw new InvalidOperationException("Cannot peek empty stack");
        return _storage[_size - 1];
    }
}

class Program {
    static void Main() {
        var stack = new ArrayStack(100);
        stack.Push(42);
        stack.Push(99);
        Console.WriteLine($"Top: {stack.Peek()}");
        Console.WriteLine($"Popped: {stack.Pop()}");
    }
}

C++ Version

#include <iostream>
#include <stdexcept>
#include <vector>

template<typename T>
class ArrayStack {
private:
    std::vector<T> buffer;
    size_t count;

public:
    explicit ArrayStack(size_t cap) : buffer(cap), count(0) {}

    bool empty() const { return count == 0; }
    bool full() const { return count == buffer.size(); }

    void push(const T& val) {
        if (full()) throw std::overflow_error("stack overflow");
        buffer[count++] = val;
    }

    T pop() {
        if (empty()) throw std::underflow_error("stack underflow");
        return buffer[--count];
    }

    const T& top() const {
        if (empty()) throw std::runtime_error("cannot access top of empty stack");
        return buffer[count - 1];
    }
};

int main() {
    ArrayStack<int> s(100);
    s.push(42);
    s.push(99);
    std::cout << "Top: " << s.top() << '\n';
    std::cout << "Popped: " << s.pop() << '\n';
    return 0;
}

Array-Based Circular Queue Implementation

A circular queue uses modulo arithmetic to reuse array space efficiently. It tracks start (oldest element) and end (next insertion point). Capacity is one less than array size to distinguish full/empty states.

Core Operations

  • Initialize: Set start = end = 0.
  • Enqueue: Assign to data[end], update end = (end + 1) % capacity.
  • Dequeue: Read from data[start], update start = (start + 1) % capacity.
  • Front: Return data[start] if non-empty.
  • IsEmpty: start == end.
  • IsFull: (end + 1) % capacity == start.

C Version

#include <stdio.h>
#include <stdbool.h>

#define QUEUE_CAPACITY 101  // actual usable slots = 100

typedef struct {
    int items[QUEUE_CAPACITY];
    size_t begin;
    size_t finish;
} CircularQueue;

void queue_init(CircularQueue* q) {
    q->begin = q->finish = 0;
}

bool queue_is_empty(const CircularQueue* q) { return q->begin == q->finish; }

bool queue_is_full(const CircularQueue* q) {
    return (q->finish + 1) % QUEUE_CAPACITY == q->begin;
}

void queue_enqueue(CircularQueue* q, int item) {
    if (queue_is_full(q)) {
        fprintf(stderr, "Error: queue overflow\n");
        return;
    }
    q->items[q->finish] = item;
    q->finish = (q->finish + 1) % QUEUE_CAPACITY;
}

int queue_dequeue(CircularQueue* q) {
    if (queue_is_empty(q)) {
        fprintf(stderr, "Error: queue underflow\n");
        return -1;
    }
    int val = q->items[q->begin];
    q->begin = (q->begin + 1) % QUEUE_CAPACITY;
    return val;
}

int queue_front(const CircularQueue* q) {
    if (queue_is_empty(q)) {
        fprintf(stderr, "Error: cannot read front of empty queue\n");
        return -1;
    }
    return q->items[q->begin];
}

int main() {
    CircularQueue q;
    queue_init(&q);
    queue_enqueue(&q, 100);
    queue_enqueue(&q, 200);
    printf("Front: %d\n", queue_front(&q));
    printf("Dequeued: %d\n", queue_dequeue(&q));
    return 0;
}

C# Version

using System;

class CircularQueue {
    private readonly int[] _buffer;
    private int _head;
    private int _tail;

    public CircularQueue(int capacity) {
        _buffer = new int[capacity + 1]; // +1 for sentinel
        _head = _tail = 0;
    }

    public bool IsEmpty => _head == _tail;
    public bool IsFull => (_tail + 1) % _buffer.Length == _head;

    public void Enqueue(int value) {
        if (IsFull) throw new InvalidOperationException("Queue overflow");
        _buffer[_tail] = value;
        _tail = (_tail + 1) % _buffer.Length;
    }

    public int Dequeue() {
        if (IsEmpty) throw new InvalidOperationException("Queue underflow");
        int val = _buffer[_head];
        _head = (_head + 1) % _buffer.Length;
        return val;
    }

    public int Front() {
        if (IsEmpty) throw new InvalidOperationException("Cannot read front of empty queue");
        return _buffer[_head];
    }
}

class Program {
    static void Main() {
        var q = new CircularQueue(100);
        q.Enqueue(100);
        q.Enqueue(200);
        Console.WriteLine($"Front: {q.Front()}");
        Console.WriteLine($"Dequeued: {q.Dequeue()}");
    }
}

C++ Version

#include <iostream>
#include <stdexcept>
#include <vector>

template<typename T>
class CircularQueue {
private:
    std::vector<T> storage;
    size_t head;
    size_t tail;

    size_t capacity() const { return storage.size(); }

public:
    explicit CircularQueue(size_t cap) : storage(cap + 1), head(0), tail(0) {}

    bool empty() const { return head == tail; }
    bool full() const { return (tail + 1) % capacity() == head; }

    void enqueue(const T& val) {
        if (full()) throw std::overflow_error("queue overflow");
        storage[tail] = val;
        tail = (tail + 1) % capacity();
    }

    T dequeue() {
        if (empty()) throw std::underflow_error("queue underflow");
        T val = storage[head];
        head = (head + 1) % capacity();
        return val;
    }

    const T& front() const {
        if (empty()) throw std::runtime_error("cannot access front of empty queue");
        return storage[head];
    }
};

int main() {
    CircularQueue<int> q(100);
    q.enqueue(100);
    q.enqueue(200);
    std::cout << "Front: " << q.front() << '\n';
    std::cout << "Dequeued: " << q.dequeue() << '\n';
    return 0;
}

Tags: data-structures Arrays stack Queue C

Posted on Sat, 09 May 2026 14:20:56 +0000 by phpion