K&R C Programs Exercise 4-11

Exercise 4-11. Modify getop so that it doesn’t need to use ungetch. Hint: use an internal static variable.

In the original calculator, getop calls ungetch once: when it reads a non-digit character to terminate a number, it pushes that character back so the next call to getop will see it. The fix: instead of pushing back, store the lookahead character in a static local variable lastc, initialized to EOF. At the start of each call, check lastc first. This is the same technique as a single-character pushback buffer, but it lives inside getop itself — no shared state with getch.

Solution

/* K&R Exercise 4-11 — getop without ungetch, using a static variable
 * Compile: gcc -ansi -Wall ex4-11.c -o ex4-11 */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define MAXOP  100
#define NUMBER '0'
#define MAXVAL 100

static double val[MAXVAL];
static int sp = 0;

void   push(double f) { if (sp < MAXVAL) val[sp++] = f; }
double pop(void)      { return sp > 0 ? val[--sp] : 0.0; }

/* No getch/ungetch needed */

int getop(char s[])
{
    static int lastc = EOF;   /* character read ahead but not yet consumed */
    int i, c;

    /* Use the saved character if there is one; otherwise read from stdin */
    c = (lastc != EOF) ? lastc : getchar();
    lastc = EOF;

    /* skip leading whitespace */
    while (c == ' ' || c == '\t')
        c = getchar();

    s[0] = c;
    s[1] = '\0';

    if (!isdigit(c) && c != '.')
        return c;

    i = 0;
    if (isdigit(c))
        while (isdigit(s[++i] = c = getchar()))
            ;
    if (c == '.')
        while (isdigit(s[++i] = c = getchar()))
            ;
    s[i] = '\0';

    if (c != EOF)
        lastc = c;   /* save the lookahead instead of calling ungetch */

    return NUMBER;
}

int main(void)
{
    int type;
    double op2;
    char s[MAXOP];

    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 (pop()) push(pop()/op2); break;
        case '\n':   printf("\t%.8g\n", pop()); break;
        }
    }
    return 0;
}

Compile and Test

gcc -ansi -Wall ex4-11.c -o ex4-11
echo "2 3 + 4 *" | ./ex4-11   # 20

Sample Output

        20

What This Exercise Teaches

  • static locals as private state — a static local variable persists across calls to the same function; it’s the simplest form of encapsulated state in C
  • Internalizing a dependency — moving the pushback from a shared module (ungetch) to inside getop reduces coupling; getop now has no external dependencies beyond getchar
  • Same invariant, different mechanism — whether you use ungetch or a static lastc, the invariant is identical: one character of lookahead is saved and returned at the start of the next call

Set Up Your C Environment

← Exercise 4-10  | 
Chapter 4 Solutions  | 
Exercise 4-12 →

Book: The C Programming Language, 2nd Ed — Kernighan & Ritchie

1 comment on “K&R C Programs Exercise 4-11

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>