K&R C Programs Exercise 4-9

Exercise 4-9. Our getch and ungetch do not handle a pushed-back EOF correctly. Decide what their properties should be if an EOF is pushed back, then implement your decision.

The bug: K&R’s original implementation uses char buf[BUFSIZE]. When ungetch(EOF) is called, EOF (typically -1) is stored as char. On platforms where char is unsigned, -1 wraps to 255, which is not EOF when read back. The result is corrupted input on any platform where char is unsigned (ARM, many embedded targets).

The fix: change the buffer type from char[] to int[] so that EOF (-1) is preserved exactly. The decision: pushing back EOF should cause the next getch to return EOF, faithfully representing the end-of-file condition.

Solution

/* K&R Exercise 4-9 — getch/ungetch that handle pushed-back EOF
 * Compile: gcc -ansi -Wall ex4-9.c -o ex4-9 */
#include <stdio.h>

#define BUFSIZE 100

static int buf[BUFSIZE];   /* int[], NOT char[] — preserves EOF (-1) */
static int bufp = 0;

int getch(void)
{
    return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c)
{
    if (bufp >= BUFSIZE)
        printf("ungetch: too many characters\n");
    else
        buf[bufp++] = c;
}

int main(void)
{
    int c;

    /* Push back a regular character then EOF */
    ungetch('A');
    ungetch(EOF);

    c = getch();
    printf("first getch: %s\n", c == EOF ? "EOF" : "not EOF");  /* EOF */

    c = getch();
    printf("second getch: %c\n", c);  /* A */

    return 0;
}

Why char Fails

static char cbuf[100];   /* BROKEN on unsigned-char platforms */
/* ungetch(EOF): stores (char)(-1) = 255 (unsigned) or -1 (signed) */
/* getch returns 255, not EOF, on unsigned-char platforms           */
/* safe cast: (unsigned char)(-1) != EOF                           */

static int ibuf[100];    /* CORRECT: int preserves -1 as -1 */

Compile and Run

gcc -ansi -Wall ex4-9.c -o ex4-9
./ex4-9

Sample Output

first getch: EOF
second getch: A

What This Exercise Teaches

  • Signed vs unsigned char — the C standard leaves char signedness implementation-defined; code that depends on it being signed is non-portable
  • Why getchar returns int — exactly this reason: it must be able to return all 256 character values and EOF (-1), which requires more than 8 bits; int is the correct type for any variable holding a character-or-EOF
  • Designing for edge cases — the exercise forces you to think about what the correct behaviour should be before implementing; choosing to propagate EOF faithfully is the right answer here

Set Up Your C Environment

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

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>