K&R C Programs Exercise 5-1

Exercise 5-1. As written, getint treats a + or - not followed by a digit as a valid representation of zero. Fix getint so that it pushes such a character back on the input.

K&R’s getint from Section 5.2 reads an optional sign then digits. The bug: if + or - appears but the next character isn’t a digit, it returns 0 and the non-digit is consumed. The fix: peek ahead after the sign; if it’s not a digit, push both characters back (the non-digit first, then the sign) and return the sign character so the caller knows nothing was read.

Solution

/* K&R Exercise 5-1 — getint with pushback fix
 * Compile: gcc -ansi -Wall ex5-1.c -o ex5-1 */
#include <stdio.h>
#include <ctype.h>

#define BUFSIZE 100
static char buf[BUFSIZE];
static int  bufp = 0;

int  getch(void)    { return (bufp > 0) ? buf[--bufp] : getchar(); }
void ungetch(int c) { if (bufp < BUFSIZE) buf[bufp++] = c; }

int getint(int *pn)
{
    int c, sign, next;

    while (isspace(c = getch()))
        ;

    if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
        ungetch(c);
        return 0;
    }

    sign = (c == '-') ? -1 : 1;

    if (c == '+' || c == '-') {
        next = getch();
        if (!isdigit(next)) {       /* sign not followed by digit */
            ungetch(next);          /* push back non-digit */
            ungetch(c);             /* push back sign */
            return c;               /* signal: no integer was read */
        }
        c = next;
    }

    for (*pn = 0; isdigit(c); c = getch())
        *pn = 10 * *pn + (c - '0');

    *pn *= sign;
    if (c != EOF) ungetch(c);
    return c;
}

int main(void)
{
    int n, ret;

    /* Test: standalone sign characters should not be consumed as zero */
    /* Simulate input "- 42" — minus not followed immediately by digit */
    char *inputs[] = { "42", "-7", "+", "-", "+99" };
    int   i;

    for (i = 0; i < 5; i++) {
        /* reload getch buffer */
        int j;
        bufp = 0;
        for (j = 0; inputs[i][j]; j++)
            buf[j] = inputs[i][j];
        buf[j] = '\n';
        bufp = j + 1;
        /* reverse so getch reads forward */
        { int l = 0, r = bufp - 1; char t;
          while (l < r) { t = buf[l]; buf[l++] = buf[r]; buf[r--] = t; } }

        ret = getint(&n);
        if (isdigit(ret) || ret == EOF || ret == '\n')
            printf("input %-5s  → n=%d\n", inputs[i], n);
        else
            printf("input %-5s  → pushed back '%c' (no integer)\n",
                   inputs[i], ret);
    }
    return 0;
}

The Core Fix

/* Before fix: */
if (c == '+' || c == '-')
    c = getch();          /* if next char is not a digit, c is lost */

/* After fix: */
if (c == '+' || c == '-') {
    next = getch();
    if (!isdigit(next)) {
        ungetch(next);    /* push back non-digit */
        ungetch(c);       /* push back sign */
        return c;         /* caller sees sign was not start of number */
    }
    c = next;
}

What This Exercise Teaches

  • Lookahead and pushback — the sign character cannot be committed to until you know what follows it; always have an “undo” path
  • Order of ungetch matters — push back in reverse of read order (non-digit first, then sign) so they come back out in the original order
  • Return value semantics — returning the sign character (not 0) lets the caller distinguish “no integer” from “integer 0”

Set Up Your C Environment

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

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>