K&R C Programs Exercise 4-3

Exercise 4-3. Given the basic framework, it’s straightforward to extend the calculator. Add the modulus (%) operator and provisions for negative numbers.

This exercise extends the RPN desk calculator from K&R Section 4.3. Two independent additions:

  1. Modulus operator % — pop two operands, cast to int, apply %, push result. Floating-point modulus is mathematically well-defined but % in C only works on integers, so truncation is required.
  2. Negative number inputgetop must distinguish a unary minus (start of a negative number) from the binary minus operator. The rule: if - is immediately followed by a digit or ., it is part of a number; otherwise it is an operator.

Key Changes to the Calculator

/* K&R Exercise 4-3 — RPN calculator: % operator and negative numbers
 * Compile: gcc -ansi -Wall ex4-3.c -o ex4-3 */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.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;
    else printf("error: stack full\n");
}
double pop(void) {
    if (sp > 0) return val[--sp];
    printf("error: stack empty\n"); return 0.0;
}

static int buf = -1; /* ungetch buffer */
int getch(void)  { return (buf >= 0) ? (buf = -1, buf+1-1, buf = -1, getchar()) : getchar(); }
/* simpler: */
static int _buf = EOF;
int gc(void)  { int c = _buf; _buf = EOF; return (c != EOF) ? c : getchar(); }
void ugc(int c) { _buf = c; }

/* getop — returns NUMBER for a number token, else the operator char.
 * Handles negative numbers: if '-' is followed by digit or '.', it's a number. */
int getop(char s[])
{
    int i, c, next;
    while ((s[0] = c = gc()) == ' ' || c == '\t')
        ;
    s[1] = '\0';
    if (!isdigit(c) && c != '.' && c != '-')
        return c;
    if (c == '-') {
        next = gc();
        if (!isdigit(next) && next != '.') {
            ugc(next);
            return '-';          /* binary minus operator */
        }
        /* unary minus: fall through, prepend '-' to the number */
        s[1] = c = next;
        i = 1;
    } else {
        i = 0;
    }
    if (isdigit(c))
        while (isdigit(s[++i] = c = gc()))
            ;
    if (c == '.')
        while (isdigit(s[++i] = c = gc()))
            ;
    s[i] = '\0';
    if (c != EOF) ugc(c);
    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 (op2 != 0.0) push(pop() / op2);
            else printf("error: zero divisor\n");
            break;
        case '%':                        /* Exercise 4-3: modulus */
            op2 = pop();
            if (op2 != 0.0) push((int)pop() % (int)op2);
            else printf("error: zero divisor\n");
            break;
        case '\n':
            printf("\t%.8g\n", pop());
            break;
        default:
            printf("error: unknown command %c\n", type);
            break;
        }
    }
    return 0;
}

Test It

echo "10 3 %" | ./ex4-3      # 1
echo "-5 2 +" | ./ex4-3     # -3
echo "-3.14 2 *" | ./ex4-3  # -6.28

Sample Output

        1
        -3
        -6.28

What This Exercise Teaches

  • Context-sensitive lexing — the same - character means two different things; one lookahead character resolves the ambiguity
  • Float-to-int truncation for % — C’s % requires integer operands; casting truncates toward zero, which is the standard C99+ behaviour
  • Operator vs number parsing boundary — the key insight is that getop must peek ahead and push back unused characters

Set Up Your C Environment

← Exercise 4-2  | 
Chapter 4 Solutions  | 
Exercise 4-4 →

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

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>