Exercise 4-10. An alternate organization uses
getlineto read an entire input line; this makesgetchandungetchunnecessary. Revise the calculator to use this approach.
The original calculator reads the input one character at a time via getch/ungetch. This exercise replaces that machinery with a line-buffer approach: read the whole line into a static array, then have getop scan through it using an index. No pushback is needed because backing up the index is free — just decrement it. The tradeoff: the line-buffer approach is simpler but loses the ability to handle multi-line tokens; the original approach works with any input stream.
Solution
/* K&R Exercise 4-10 — RPN calculator using getline (no getch/ungetch)
* Compile: gcc -ansi -Wall ex4-10.c -o ex4-10 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXOP 100
#define MAXLINE 1000
#define NUMBER '0'
#define MAXVAL 100
static double val[MAXVAL];
static int sp = 0;
void push(double f) { if (sp < MAXVAL) val[sp++] = f; else printf("stack full\n"); }
double pop(void) { return sp > 0 ? val[--sp] : (printf("stack empty\n"), 0.0); }
/* Line buffer — getop scans through it via an index */
static char line[MAXLINE];
static int li = 0; /* next position to read in line[] */
int getline_buf(void)
{
if (fgets(line, MAXLINE, stdin) == NULL) {
line[0] = '\0';
return 0;
}
li = 0;
return 1;
}
/* getop using line buffer index — no getch/ungetch */
int getop(char s[])
{
int i, c;
/* skip whitespace; if we reach end of line, read a new one */
while (line[li] == ' ' || line[li] == '\t')
li++;
if (line[li] == '\0' || line[li] == '\n') {
if (!getline_buf()) return EOF;
return '\n';
}
s[0] = c = line[li++];
s[1] = '\0';
if (!isdigit(c) && c != '.')
return c;
i = 0;
if (isdigit(c))
while (isdigit(s[++i] = c = line[li++]))
;
if (c == '.')
while (isdigit(s[++i] = c = line[li++]))
;
s[i] = '\0';
if (c != '\0') li--; /* push back: just decrement the index */
return NUMBER;
}
int main(void)
{
int type;
double op2;
char s[MAXOP];
if (!getline_buf()) return 0;
while ((type = getop(s)) != EOF) {
switch (type) {
case NUMBER: push(atof(s)); break;
case '+': push(pop() + pop()); break;
case '*': push(pop() * pop()); break;
case '-': op2 = pop(); push(pop() - op2); break;
case '/': op2 = pop(); if (op2) push(pop()/op2); break;
case '\n': printf("\t%.8g\n", pop()); break;
default: printf("unknown: %c\n", type); break;
}
}
return 0;
}
Compile and Test
gcc -ansi -Wall ex4-10.c -o ex4-10
echo "3 4 + 2 *" | ./ex4-10 # 14
echo "10 2 /" | ./ex4-10 # 5
Sample Output
14
5
What This Exercise Teaches
- Two design approaches for lexing — character stream (getch/ungetch, works with any stream, handles multi-line tokens) vs line buffer (simpler index arithmetic, “pushback” is free)
- Pushback without a buffer — decrementing an index is equivalent to ungetch; only valid because the character was already in the buffer
- fgets vs getchar —
fgetsreads a whole line at once; it also null-terminates, making index scanning safe without a sentinel check
Set Up Your C Environment
← Exercise 4-9 |
Chapter 4 Solutions |
Exercise 4-11 →
Book: The C Programming Language, 2nd Ed — Kernighan & Ritchie
1 comment on “K&R C Programs Exercise 4-10”
What hosting sites will allow my blog page to make cash off offers being placed on my blog?