Lesson 10 · 10 of 20
A stack and a queue · C
Use a stack in C to check whether the brackets in an expression are balanced, and a circular queue for a printer's jobs.

A stack (LIFO, last in, first out) only lets you add and remove at the top, like a pile of plates. Here it is an array stack with an index top: push is stack[top++] = c and pop is stack[--top].
balanced checks the brackets in an expression. Every opener ((, [ or {) is pushed. Every closer must match the last opener left on the stack: "([{"[closer - ")]}"] gives the opener for the closer just found, because both strings list them in the same order. If the stack is empty or they do not match, it is unbalanced; and if something is still open at the end, as in ((total), it is too.
A queue (FIFO, first in, first out) serves in order of arrival, like a printer's. Queue is a ring buffer: head is the first one waiting and count how many there are. enqueue writes at position (head + count) % CAP and dequeue reads at head and moves it forward.
% CAP wraps the indexes back to 0 at the end of the array, so the slot freed by each printed job is reused and elements never have to move.
Both structures have a fixed capacity here, CAP, and balanced returns 0 if the stack would overflow. With what you saw in the realloc lesson you can turn them into structures that grow.
Code · main.c
#include <stdio.h>#include <string.h>#define CAP 16 // room in the stack and in the queueint balanced(const char *text) { char stack[CAP]; int top = 0; // a stack (LIFO): last in, first out for (; *text; text++) { const char *closer = strchr(")]}", *text); if (strchr("([{", *text)) { if (top == CAP) return 0; // too deep for our stack stack[top++] = *text; // push } else if (closer && (top == 0 || stack[--top] != "([{"[closer - ")]}"])) return 0; // pop: it must be the matching opener } return top == 0; // nothing left open}typedef struct { const char *items[CAP]; int head, count; } Queue; // FIFO ring buffervoid enqueue(Queue *q, const char *job) { q->items[(q->head + q->count++) % CAP] = job; }const char *dequeue(Queue *q) { // head moves forward and wraps around const char *job = q->items[q->head]; q->head = (q->head + 1) % CAP; q->count--; return job;}int main(void) { const char *exprs[] = {"(a[i] + b) * {c}", "f(x[0)]", "((total)"}; for (int i = 0; i < 3; i++) printf("%-18s %s\n", exprs[i], balanced(exprs[i]) ? "balanced" : "NOT balanced"); Queue printer = {.head = 0, .count = 0}; enqueue(&printer, "invoice.pdf"); enqueue(&printer, "photo.png"); printf("Printing %s\n", dequeue(&printer)); enqueue(&printer, "report.docx"); while (printer.count > 0) printf("Printing %s\n", dequeue(&printer)); return 0;}Output · cc main.c -o main && ./main
(a[i] + b) * {c} balanced
f(x[0)] NOT balanced
((total) NOT balanced
Printing invoice.pdf
Printing photo.png
Printing report.docxKey points
- Stack: last in, first out.
- Queue: first in, first out.
top++pushes and--toppops.- A ring buffer moves on with
% CAPand never shifts data.
Exercise
Add an int is_full(const Queue *q) function to the queue, make enqueue return 0 when it is full and test it with CAP set to 3.