K&R C Programs Exercise 4-6

Exercise 4-6. Add commands for handling variables. (It’s easy to provide for twenty-six variables with single-letter names.) Add a variable for the most recently printed value.

Twenty-six variables map naturally to an array var[26] indexed by c - 'a'. The protocol: a lowercase letter pushes its variable’s value; = assigns the top of the stack to the variable named by the next token (without popping). A special $ variable holds the most recently printed value — updated automatically every time \n prints the result. The tricky design decision is that = keeps the value on the stack, so 3 x = 4 y = assigns both without breaking the calculation flow.

Key Additions

/* K&R Exercise 4-6 — RPN calculator: variables and last-value
 * Add to the calculator from Exercise 4-5.
 * Compile: gcc -ansi -Wall ex4-6.c -o ex4-6 -lm */

static double var[26];     /* a..z */
static double last = 0.0;  /* $ = most recently printed value */

/* In getop: uppercase letters return the char directly (operator dispatch).
 * Lower-case letters are handled below. */

/* In the main switch, add: */

/* push variable value */
/* (In getop, a single lowercase letter should return VARIABLE='v'
 *  with s[0] = the letter. For simplicity here we handle it in main.) */

/* Assignment: = varname stores top-of-stack into var without popping */
case '=':
    /* peek at next non-space token to get variable name */
    {
        int c;
        while ((c = gc()) == ' ' || c == '\t')
            ;
        if (c >= 'a' && c <= 'z')
            var[c - 'a'] = val[sp > 0 ? sp-1 : 0];
        else
            printf("error: = must be followed by a variable name\n");
    }
    break;

/* $ pushes the last-printed value */
case '$':
    push(last);
    break;

/* Update last when printing (in the '\n' case): */
case '\n':
    last = pop();
    printf("\t%.8g\n", last);
    break;

Complete Working Demo

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>

#define MAXVAL 100
#define NUMBER '0'

static double val[MAXVAL];
static int sp = 0;
static double var[26];
static double last = 0.0;

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

static int _buf = EOF;
int  gc(void)   { int c = _buf; _buf = EOF; return (c != EOF) ? c : getchar(); }
void ugc(int c) { _buf = c; }

int getop(char s[])
{
    int i, c;
    while ((s[0] = c = gc()) == ' ' || c == '\t')
        ;
    s[1] = '\0';
    if (c >= 'a' && c <= 'z') return 'v';  /* variable name in s[0] */
    if (!isdigit(c) && c != '.') return c;
    i = 0;
    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[100];

    while ((type = getop(s)) != EOF) {
        switch (type) {
        case NUMBER: push(atof(s)); break;
        case '+':    push(pop() + pop()); break;
        case '-':    op2 = pop(); push(pop() - op2); break;
        case '*':    push(pop() * pop()); break;
        case '/':    op2 = pop(); if (op2) push(pop()/op2); break;
        case 'v':    push(var[s[0]-'a']); break;  /* push variable */
        case '=':    /* assign TOS to next variable */
            { int c; while((c=gc())==' '||c=='\t'); if(c>='a'&&c<='z') var[c-'a']=val[sp>0?sp-1:0]; } break;
        case '$':    push(last); break;
        case '\n':   last = pop(); printf("\t%.8g\n", last); break;
        }
    }
    return 0;
}

Test It

printf "3.14159\n= p\np\n2 p * *\n" | ./ex4-6
# Store pi in p, compute 2*pi*pi

What This Exercise Teaches

  • State outside the stack — variables and last are module-level state; the stack itself is stateless between operations
  • Assignment without pop= peeks rather than pops, so the value stays available for the next operation
  • Special variable $ — automatically updated on every print; allows using the previous result without re-typing
  • Design choice — uppercase vs lowercase for store/recall is one convention; push-on-read plus explicit = is another; neither is canonically correct

Set Up Your C Environment

← Exercise 4-5  | 
Chapter 4 Solutions  | 
Exercise 4-7 →

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

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

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>