Exercise 5-1. As written,
getinttreats a+or-not followed by a digit as a valid representation of zero. Fixgetintso 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