Exercise 7-5. Rewrite the postfix calculator of Chapter 4 to use
scanfand/orsscanfto do the input and number conversion.
The original Chapter 4 calculator used a custom getop() that read characters one at a time with getch/ungetch to recognise numbers vs operators. With scanf we replace that with a simpler approach: read one whitespace-delimited token with scanf("%s",...), then use sscanf to test whether it is a number.
Solution
/* K&R Exercise 7-5 — postfix RPN calculator using scanf
* Compile: gcc -ansi -Wall ex7-5.c -o rpn
* Usage: echo "3 4 + 2 * ." | ./rpn -> 14 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAXSTACK 100
#define MAXTOKEN 100
static double stack[MAXSTACK];
static int sp = 0;
static void push(double val)
{
if (sp < MAXSTACK)
stack[sp++] = val;
else
fprintf(stderr, "error: stack overflow\n");
}
static double pop(void)
{
if (sp > 0)
return stack[--sp];
fprintf(stderr, "error: stack underflow\n");
return 0.0;
}
int main(void)
{
char token[MAXTOKEN];
double val;
double a, b;
while (scanf("%99s", token) == 1) {
if (sscanf(token, "%lf", &val) == 1) {
push(val);
} else if (strlen(token) == 1) {
switch (token[0]) {
case '+': push(pop() + pop()); break;
case '*': push(pop() * pop()); break;
case '-': b = pop(); a = pop(); push(a - b); break;
case '/': b = pop(); a = pop();
if (b == 0.0) fprintf(stderr, "error: divide by zero\n");
else push(a / b);
break;
case '%': b = pop(); a = pop();
if (b == 0.0) fprintf(stderr, "error: modulo by zero\n");
else push(fmod(a, b));
break;
case '.': printf("\t%.8g\n", pop()); break;
default:
fprintf(stderr, "unknown operator: %s\n", token);
break;
}
} else {
fprintf(stderr, "unknown token: %s\n", token);
}
}
return 0;
}
Compile and Test
gcc -ansi -Wall ex7-5.c -o rpn -lm
echo "3 4 + ." | ./rpn # 7
echo "3 4 + 2 * ." | ./rpn # 14
echo "15 7 1 1 + - / 3 * 2 1 1 + + - ." | ./rpn # 5
echo "10 3 % ." | ./rpn # 1
Expected Output
7
14
5
1
How scanf Simplifies the Input
The original getop() loop:
- Read one character at a time
- Push back non-digit characters with
ungetch - Accumulate digit characters into a buffer
- Return NUMBER vs operator code
With scanf:
/* One call reads the next whitespace-delimited token */
scanf("%99s", token);
/* One call tests if it is a number */
sscanf(token, "%lf", &val);
sscanf returns 1 on success (full number parsed) or 0 if the string isn’t a valid number — exactly the switch we need.
What This Exercise Teaches
sscanfas a type test — tryingsscanf(token, "%lf", &val)and checking the return value cleanly replaces manual character-by-character digit detection- Non-commutativity of subtraction and division —
3 4 -means 3−4, not 4−3; the operands must be popped in order:b = pop(); a = pop(); push(a - b) - Width limit in
scanf—"%99s"caps the read at 99 characters, preventing overflow into the 100-bytetokenbuffer; never use bare"%s"with an unknown-length input
Set Up Your C Environment
← Exercise 7-4 |
Chapter 7 Solutions |
Exercise 7-6 →
Book: The C Programming Language, 2nd Ed — Kernighan & Ritchie