Stack using array
An array-based stack stores elements in a contiguous block of memory and tracks the top with an integer index. Push and pop at the top are O(1) time. The trade-off is a fixed maximum capacity (unless you switch to a dynamic array). This page uses the common convention top == -1 for an empty stack and top == capacity - 1 when full.
- Representation — array,
top, and capacity - Operations — how push, pop, and peek update the index
- Example in C — struct, init, full/empty, push/pop/peek
- Trade-offs — vs linked list and dynamic growth
1) Array representation
You need a place to hold values, a record of where the top is, and a limit on how many items fit. At its simplest that is just an array and an integer top (you can group both in a struct later for convenience).
| Component | Role | Notes |
|---|---|---|
items[] |
Stores stack elements from index 0 up to top. |
Can be int, double, or a typedef type; same idea for larger structs. |
top |
Index of the current top element; -1 means empty. |
Some codebases use top as “next free slot” instead—stay consistent in one project. |
| Capacity | Maximum number of elements (MAX macro or field). |
Stack is full when top == capacity - 1 (with top == -1 empty). |
2) Mapping operations to the array
All mutations adjust top by one and read or write items[top]. Always check full before push and empty before pop or peek.
| Operation | Array steps | Failure case |
|---|---|---|
push(x) |
If not full: top++, then items[top] = x. |
Overflow if already full. |
pop |
If not empty: read items[top], then top--. |
Underflow if empty. |
peek |
If not empty: return items[top] without changing top. |
Underflow if empty. |
isEmpty |
True when top < 0 (or top == -1). |
— |
isFull |
True when top == capacity - 1. |
— |
3) Example in C
Below, the stack is a fixed int array plus an index top, both kept at file scope with static so helpers need no struct, no pointer parameters, and no & in main. Functions return 1 on success and 0 on overflow or underflow; after a successful peek or pop, read the value from stack_last.
#include <stdio.h>
#define MAX 100
/* One stack for this file: elements live in stack[0..top], top == -1 when empty. */
static int stack[MAX];
static int top;
/* After stack_peek or stack_pop returns 1, the top value is here (no extra out-parameters). */
static int stack_last;
void stack_init(void) {
top = -1;
}
int stack_is_empty(void) {
return top < 0;
}
int stack_is_full(void) {
/* Last valid index is MAX - 1, so full when top sits there. */
return top >= MAX - 1;
}
/* Returns 1 on success, 0 if overflow (array full). */
int stack_push(int value) {
if (stack_is_full())
return 0;
top++;
stack[top] = value;
return 1;
}
/* Returns 1 on success, 0 if underflow (empty). Popped value is stored in stack_last. */
int stack_pop(void) {
if (stack_is_empty())
return 0;
stack_last = stack[top];
top--;
return 1;
}
/* Returns 1 on success, 0 if underflow. Current top (without removing) is stack_last. */
int stack_peek(void) {
if (stack_is_empty())
return 0;
stack_last = stack[top];
return 1;
}
int main(void) {
stack_init();
stack_push(10);
stack_push(20);
if (stack_peek())
printf("peek: %d\n", stack_last);
if (stack_pop())
printf("pop: %d\n", stack_last);
return 0;
}
This layout is easy to read; larger programs usually pass the array and top explicitly or wrap them in a type so you can have more than one stack.
Explanation of the program output
Here’s the explanation of the program’s output in table format:
| Step | Operation | Stack state (top to bottom) | Return value | stack_last value |
Output |
|---|---|---|---|---|---|
| 1 | stack_init() |
[] (empty, top = -1) |
(void) | unchanged | (none) |
| 2 | stack_push(10) |
[10] (top = 0) |
1 (success) |
unchanged | (none) |
| 3 | stack_push(20) |
[20, 10] (top = 1) |
1 (success) |
unchanged | (none) |
| 4 | stack_peek() |
[20, 10] (unchanged, top = 1) |
1 (success) |
20 (top value) |
peek: 20 |
| 5 | stack_pop() |
[10] (top = 0) |
1 (success) |
20 (popped value) |
pop: 20 |
| 6 | Program ends | [10] (still in stack) |
— | — | — |
| Line | Output |
|---|---|
| 1 | peek: 20 |
| 2 | pop: 20 |
Key points
| Behavior | Explanation |
|---|---|
Peek shows 20 |
Stack is LIFO (Last-In-First-Out), so the most recent push (20) is on top. |
Pop shows 20 |
The same top element (20) is removed and returned. |
| No output for pushes | stack_push() returns a success code but doesn’t print anything. |
10 remains |
The program ends before popping the remaining element (10). |
4) Trade-offs
- Pros — Very fast and simple; excellent cache locality; no
mallocper push if the array is static or allocated once. - Cons — Fixed cap causes overflow unless you resize; wasted space if you allocate huge
MAXbut use little.
For unbounded growth from an array, use a dynamic array stack; for no fixed cap without contiguous resizing, compare with a linked-list stack. Operation definitions are summarized on Stack operations.
Key takeaway
Keep one clear invariant: top always points at the current top element, or is -1 when empty. Every push increments top then assigns; every pop reads then decrements—after checking full and empty.
Next up: Stack using dynamic array · Stack using linked list · Stack operations