HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

FIFO getch/ungetch Functions

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
functionsgetchfifoungetch

Problem

I'm currently working myself through K&R and just read about implementing getch() and ungetch().

In K&R these functions are implemented like this:

#include 

#define BUFSIZE 100
char buf[BUFSIZE];     /* buffer for ungetch */
int bufp = 0;          /* next free position in buf */

int getch(void) /* get a (possibly pushed-back) character */
{
    return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c)    /* push character back on input */
{
    if (bufp >= BUFSIZE)
        printf("ungetch: too many characters\n");
    else
        buf[bufp++] = c;
}


As you can see this is implemented like a stack (last in -> first out). This somehow bothers me. In the example:

ungetch('a');
ungetch('b');
ungetch('c');


getch()will return 'c' at the first function call. 'b' on the second function call and 'a' on the third function call. I liked the idea of getting the first 'ungetch()'-ed char at the start and the last 'ungetch'-ed char in the end.

This is what I did:

#include 

#define BUFSIZE 10
static int reorder_buf(void);

char buf[BUFSIZE];
int bufrp = 0;    //buffer read position
int bufwp = 0;    //buffer write position

int getch(void)
{
    if (bufrp  0)
    {
        int i;
        for(i = 0; bufrp < bufwp; bufrp++, i++)
             buf[i] = buf[bufrp];

        bufrp = 0;
        bufwp = i;
        return 1;
     } else
     {
         return 0;
     }
}


I also had the idea to replace the error message in ungetch() with returning an int, which includes the information if the unget process was successful and provides it to the caller.

Solution

reorder_buf() is horribly inefficient, and it's unnecessary if you use the buffer as a circular-list. What you want is called a ring buffer.

/* Store up to 10 characters */
#define BUFSIZE 11

char buf[BUFSIZE];
int qhead = 0, qtail = 0;

int getch(void) {
    if (qhead != qtail) {
        int c = buf[qhead];
        qhead = (qhead + 1) % BUFSIZE;
        return c;
    } else {
        return getchar();
    }
}

void ungetch(int c) {
    if ((qtail + 1) % BUFSIZE == qhead) {
        fprintf(stderr, "Buffer full, dropped %c.\n", c);
    } else {
        buf[qtail] = c;
        qtail = (qtail + 1) % BUFSIZE;
    }
}


Errors should go to stderr rather than stdout.

Code Snippets

/* Store up to 10 characters */
#define BUFSIZE 11

char buf[BUFSIZE];
int qhead = 0, qtail = 0;

int getch(void) {
    if (qhead != qtail) {
        int c = buf[qhead];
        qhead = (qhead + 1) % BUFSIZE;
        return c;
    } else {
        return getchar();
    }
}

void ungetch(int c) {
    if ((qtail + 1) % BUFSIZE == qhead) {
        fprintf(stderr, "Buffer full, dropped %c.\n", c);
    } else {
        buf[qtail] = c;
        qtail = (qtail + 1) % BUFSIZE;
    }
}

Context

StackExchange Code Review Q#110400, answer score: 2

Revisions (0)

No revisions yet.