C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
150: Implementing a Stack with Arrays
How do I actually structure a stack using an array?
The biggest mistake I see people make is trying to manage the array and the "top" index as separate, loose variables. That's a recipe for disaster once your project grows. Instead, you want to wrap them together in a struct. This keeps your stack's state bundled, which means you can pass a single pointer to your functions rather than three different arguments.
Let's imagine we're building a simple "Undo" system for a text editor. We only need to store operation IDs (integers) for now. Here is how I'd set that up:
#define MAX_SIZE 100
typedef struct {
int items[MAX_SIZE];
int top;
} UndoStack;
void initStack(UndoStack *s) {
s->top = -1; // Start at -1 because the stack is empty
}
I start top at -1. Why? Because in C, arrays are zero-indexed. If top was 0, it would look like there's already an element at the first position. Starting at -1 makes the logic for adding the first element much cleaner.
What is the logic for pushing and popping elements?
Think of a stack like a physical stack of plates. You only ever touch the top one. To "Push," you increment the index and drop the value in. To "Pop," you grab the value and decrement the index.
Here is the implementation. Notice how I'm using a pointer to the UndoStack so the functions can actually modify the original stack rather than a copy:
void push(UndoStack *s, int opId) {
if (s->top == MAX_SIZE - 1) {
// We'll talk about this "full" state in a second
return;
}
s->items[++(s->top)] = opId;
}
int pop(UndoStack *s) {
if (s->top == -1) {
return -1; // Indicate the stack is empty
}
return s->items[(s->top)--];
}
I used the prefix increment ++(s->top) inside the push function. It's a concise way of saying "move the pointer up first, then put the value there." It saves a line of code and is standard practice in C once you're comfortable with it.
How do I prevent the program from crashing when the stack is full?
This is where the term "Stack Overflow" actually comes from. Since we're using a fixed-size array, we have a hard ceiling. If you try to write to items[100] when your array is only 100 elements long, you're writing into memory you don't own. That's a segmentation fault waiting to happen.
You must always perform a boundary check before pushing. In the code above, if (s->top == MAX_SIZE - 1) handles this. If the top index has reached the last valid index of the array, the stack is full. In a professional environment, you'd probably return an error code or dynamically resize the array using realloc(), but for a standard array-based stack, a simple check and a warning is the way to go.
Similarly, you have to check for "Stack Underflow" during a pop. If top is -1 and you try to decrement it further, you'll be accessing items[-1], which is illegal memory. Always check that top != -1 before you attempt to pop.
📋 Practical Task
Build a Bracket Balancer
Your task is to create a program that checks if a string of parentheses is "balanced." A string is balanced if every opening parenthesis '(' has a corresponding closing parenthesis ')' in the correct order.
Requirements:
- Implement a stack using a
structand an array (as shown in the lesson). - The stack should store characters (
char) instead of integers. - Iterate through a string: whenever you see an opening bracket
'(', push it onto the stack. - Whenever you see a closing bracket
')', pop from the stack. - If you try to pop from an empty stack, or if there are items left on the stack after the string ends, the brackets are unbalanced.
Test Case: "(())()" should return "Balanced", while "(()" or ")(" should return "Unbalanced".
There are no comments for now.