Infix to Postfix Program in C
A complete, compilable C program that converts an infix expression to postfix using a stack — with the precedence and associativity rules handled correctly, including the two cases most classroom versions get wrong.
The complete C program
Save this as infix_to_postfix.c. It is standard C99 with no external
libraries, it compiles clean under -Wall -Wextra, and it handles
single-character operands, all six operators and nested brackets.
/* infix_to_postfix.c — convert an infix expression to postfix using a stack */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 100
char stack[MAX];
int top = -1;
void push(char c) { if (top < MAX - 1) stack[++top] = c; }
char pop(void) { return (top < 0) ? '\0' : stack[top--]; }
char peek(void) { return (top < 0) ? '\0' : stack[top]; }
int isEmpty(void) { return top == -1; }
void resetStack(void) { top = -1; }
/* Higher number = binds more tightly. 0 means "not an operator". */
int precedence(char op)
{
switch (op) {
case '^': return 3;
case '*': case '/':
case '%': return 2;
case '+': case '-': return 1;
default: return 0;
}
}
/* Only exponentiation groups right to left. */
int isRightAssociative(char op) { return op == '^'; }
/* Returns 1 on success, 0 if the expression is invalid. */
int infixToPostfix(const char *infix, char *postfix)
{
int i, j = 0;
resetStack();
for (i = 0; infix[i] != '\0'; i++) {
char c = infix[i];
if (isspace((unsigned char)c))
continue;
/* 1. Operand: straight to the output. */
if (isalnum((unsigned char)c)) {
postfix[j++] = c;
}
/* 2. Opening bracket: push as a marker. */
else if (c == '(') {
push(c);
}
/* 3. Closing bracket: pop until the matching '('. */
else if (c == ')') {
while (!isEmpty() && peek() != '(')
postfix[j++] = pop();
if (isEmpty()) {
printf("Error: unbalanced brackets - extra ')'\n");
return 0;
}
pop(); /* discard the '(' */
}
/* 4. Operator: pop everything that outranks it, then push. */
else if (precedence(c) > 0) {
while (!isEmpty() && peek() != '(' &&
(precedence(peek()) > precedence(c) ||
(precedence(peek()) == precedence(c) && !isRightAssociative(c))))
postfix[j++] = pop();
push(c);
}
else {
printf("Error: invalid character '%c'\n", c);
return 0;
}
}
/* 5. Flush whatever is left on the stack. */
while (!isEmpty()) {
char t = pop();
if (t == '(') {
printf("Error: unbalanced brackets - missing ')'\n");
return 0;
}
postfix[j++] = t;
}
postfix[j] = '\0';
return 1;
}
int main(void)
{
char infix[MAX], postfix[MAX];
printf("Enter an infix expression: ");
if (fgets(infix, sizeof infix, stdin) == NULL)
return 1;
infix[strcspn(infix, "\n")] = '\0'; /* strip the newline */
if (infixToPostfix(infix, postfix))
printf("Postfix expression: %s\n", postfix);
return 0;
}
Compile and run it
gcc -Wall -Wextra -std=c99 -o infix_to_postfix infix_to_postfix.c
./infix_to_postfix
On Windows with MinGW the command is the same but the output file needs the
extension: gcc -o infix_to_postfix.exe infix_to_postfix.c, then run
infix_to_postfix.exe. In Turbo C or an online compiler, just paste and
press run — nothing in the program is platform specific.
Sample output
Enter an infix expression: A+B*C
Postfix expression: ABC*+
Enter an infix expression: (A+B)*C-D
Postfix expression: AB+C*D-
Enter an infix expression: K+L-M*N+(O^P)*W/U/V*T+Q
Postfix expression: KL+MN*-OP^W*U/V/T*+Q+
Enter an infix expression: (A+B
Error: unbalanced brackets - missing ')'
Those are the real outputs of the program above. Paste any of the same expressions into the converter on the homepage to see the stack trace that produced them.
How the program works
The program is four small stack functions, one precedence function and one conversion loop. Nothing else.
| Function | Purpose |
|---|---|
| push(c) | Adds an operator or ( to the top of the stack, guarding against overflow |
| pop() | Removes and returns the top, or '\0' when the stack is empty |
| peek() | Reads the top without removing it, so precedence can be compared first |
| isEmpty() | Guards every peek and pop |
| resetStack() | Clears the stack before a conversion, so the function can be called more than once |
| precedence(op) | Returns 3, 2, 1 or 0 — and the 0 doubles as an "is this an operator?" test |
| isRightAssociative(op) | True only for ^ |
| infixToPostfix() | The single left-to-right scan that applies the five rules |
The conversion loop mirrors the
pseudocode line for line.
isalnum() from <ctype.h> identifies operands,
isspace() lets you type spaces in the input, and
strcspn(infix, "\n") strips the newline that fgets leaves
behind.
top is an index, not a pointer: it starts at -1 for an empty stack and always names the cell holding the most recently pushed operator.
scanf("%s", infix) stops at the first space, so
A + B would only read A. fgets reads the
whole line and takes a buffer size, so it cannot overflow. It is the right choice
in every program that reads a line of text.
The precedence function
This is where the two classic bugs live, so it is worth looking at on its own.
while (!isEmpty() && peek() != '(' &&
(precedence(peek()) > precedence(c) ||
(precedence(peek()) == precedence(c) && !isRightAssociative(c))))
postfix[j++] = pop();
push(c);
-
The
==clause. Equal precedence must also pop, for left-associative operators. Drop it andA-B-CbecomesABC--, which meansA-(B-C). -
The
!isRightAssociative(c)guard. Without it,a^b^cbecomesab^c^instead ofabc^^. -
The
peek() != '('guard. An opening bracket is a floor — popping must never go past it.
Multi-digit numbers and variable names
The program above stores one character per operand, so 12+3 converts to
123+ — the digits run together and the result is unreadable. This version
copies whole operands and separates the output with spaces, which is what you want for
anything beyond a textbook exercise.
/* Handles multi-digit numbers and multi-letter variable names. */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 256
char stack[MAX];
int top = -1;
void push(char c) { if (top < MAX - 1) stack[++top] = c; }
char pop(void) { return (top < 0) ? '\0' : stack[top--]; }
char peek(void) { return (top < 0) ? '\0' : stack[top]; }
int isEmpty(void) { return top == -1; }
void resetStack(void) { top = -1; }
int precedence(char op)
{
switch (op) {
case '^': return 3;
case '*': case '/': case '%': return 2;
case '+': case '-': return 1;
default: return 0;
}
}
int isRightAssociative(char op) { return op == '^'; }
int infixToPostfix(const char *infix, char *postfix)
{
int i = 0, j = 0;
resetStack();
while (infix[i] != '\0') {
char c = infix[i];
if (isspace((unsigned char)c)) { i++; continue; }
/* Copy a whole operand - "rate", "3.5", "250" - then one space. */
if (isalnum((unsigned char)c) || c == '_' || c == '.') {
while (infix[i] != '\0' &&
(isalnum((unsigned char)infix[i]) || infix[i] == '_' || infix[i] == '.'))
postfix[j++] = infix[i++];
postfix[j++] = ' ';
continue;
}
if (c == '(') {
push(c);
}
else if (c == ')') {
while (!isEmpty() && peek() != '(') {
postfix[j++] = pop();
postfix[j++] = ' ';
}
if (isEmpty()) {
printf("Error: unbalanced brackets - extra ')'\n");
return 0;
}
pop();
}
else if (precedence(c) > 0) {
while (!isEmpty() && peek() != '(' &&
(precedence(peek()) > precedence(c) ||
(precedence(peek()) == precedence(c) && !isRightAssociative(c)))) {
postfix[j++] = pop();
postfix[j++] = ' ';
}
push(c);
}
else {
printf("Error: invalid character '%c'\n", c);
return 0;
}
i++;
}
while (!isEmpty()) {
char t = pop();
if (t == '(') {
printf("Error: unbalanced brackets - missing ')'\n");
return 0;
}
postfix[j++] = t;
postfix[j++] = ' ';
}
if (j > 0 && postfix[j - 1] == ' ') j--; /* drop the trailing space */
postfix[j] = '\0';
return 1;
}
int main(void)
{
char infix[MAX], postfix[MAX * 2];
printf("Enter an infix expression: ");
if (fgets(infix, sizeof infix, stdin) == NULL)
return 1;
infix[strcspn(infix, "\n")] = '\0';
if (infixToPostfix(infix, postfix))
printf("Postfix expression: %s\n", postfix);
return 0;
}
| Input | Output |
|---|---|
| rate * 12 + 250 | rate 12 * 250 + |
| (price + tax) * qty | price tax + qty * |
| 3.5 * 2 + 1 | 3.5 2 * 1 + |
| x1 + y2 * z3 | x1 y2 z3 * + |
The only structural change is the operand branch: instead of copying one character it runs a small inner loop that copies the entire run of letters, digits, underscores and dots, then writes a single separating space. Every pop writes a space too, and the trailing one is trimmed at the end.
Using a linked-list stack
If your assignment asks for a dynamic stack rather than a fixed array, replace the
five stack functions with these. The names and signatures are unchanged, so
infixToPostfix() itself needs no edits at all — only
<stdlib.h> has to be included.
/* Drop-in replacement: a linked-list stack instead of a fixed array.
The four functions keep the same names and signatures, so the rest of
infixToPostfix() does not change at all. */
#include <stdlib.h>
typedef struct Node {
char data;
struct Node *next;
} Node;
Node *head = NULL; /* NULL means "empty stack" */
void push(char c)
{
Node *n = (Node *)malloc(sizeof(Node));
if (n == NULL) return; /* out of memory */
n->data = c;
n->next = head;
head = n;
}
char pop(void)
{
Node *n;
char c;
if (head == NULL) return '\0';
n = head;
c = n->data;
head = n->next;
free(n);
return c;
}
char peek(void) { return (head == NULL) ? '\0' : head->data; }
int isEmpty(void) { return head == NULL; }
/* Free every remaining node so the stack can be reused without leaking. */
void resetStack(void)
{
while (head != NULL) pop();
}
A version that writes top = -1; directly inside
infixToPostfix() will not compile once the array is gone — there is no
top any more. Hiding that one line behind resetStack() is
what makes the two stacks genuinely interchangeable, and in the linked-list version
it also frees the leftover nodes instead of leaking them.
Bugs to watch for
| Symptom | Cause | Fix |
|---|---|---|
A-B-C gives ABC-- |
Equal precedence pushes instead of popping | Add the == clause to the while condition |
a^b^c gives ab^c^ |
^ treated as left associative |
Add the !isRightAssociative(c) guard |
| Only the first character is read | scanf("%s", …) stops at whitespace |
Use fgets and strip the newline |
| A stray character at the end of the output | The newline from fgets was never removed |
infix[strcspn(infix, "\n")] = '\0'; |
| Segfault on a long expression | MAX too small, or no bounds check in push |
Size the stack at the input length and guard push |
| Garbage output on unbalanced input | A ( gets flushed into the output at the end |
Check for '(' in the final pop loop and report an error |
12+3 gives 123+ |
One character per operand | Use the multi-character version |
Frequently asked questions
How do you write an infix to postfix program in C?
Implement a character stack with push, pop,
peek and isEmpty, plus a precedence()
function returning 3 for ^, 2 for * / % and 1 for
+ -. Then scan the input string once: copy operands to the output,
push (, pop to the output until ( on a ),
and for an operator pop while the top outranks it before pushing. Finally pop
whatever is left on the stack.
Which header files does the program need?
<stdio.h> for printf and fgets,
<string.h> for strcspn, and
<ctype.h> for isalnum and isspace.
The linked-list version also needs <stdlib.h> for
malloc and free.
Why does my program print 123+ for 12+3?
Because it stores one character per operand, so the digits 1 and
2 are written separately and nothing separates them from the
3. Copy the whole run of alphanumeric characters as a single
operand and write a space after each one — that is what the
multi-character version does.
How do I handle the ^ operator correctly in C?
Give it precedence 3 and mark it right associative. In the popping condition,
an incoming right-associative operator must not pop an operator of equal
precedence — that single guard is the difference between abc^^
(correct) and ab^c^ (wrong). Note that ^ here is a
notation for exponentiation, not C's bitwise XOR.
How large should the stack array be?
The length of the input expression is always sufficient, because in the worst
case every token is on the stack at once. Sizing the stack and the input buffer
to the same MAX is the simplest safe choice, and
push should still bounds-check.
Can the same program evaluate the postfix expression too?
Yes, with a second stack that holds values instead of characters. Scan the postfix output left to right: push each operand, and on each operator pop two values, apply it, and push the result. One value is left at the end and that is the answer. The converter on this site does exactly this whenever every operand is numeric.
Related
std::stack, plus a postfix evaluator using fmod and pow.
The same converter in JavaArrayDeque as the stack, plus a postfix evaluator.
Check your program's outputRun the same expressions through the converter and compare, step by step.
The algorithm behind the codePseudocode, the precedence table and the complexity analysis.
Watch the stackSee exactly what push and pop are doing at each line of the loop.
The same converter in PythonA list as the stack, a step-by-step trace and a postfix evaluator.