K&R Exercise 1-9 (C)

Look at your program as a machine that moves between different states as it iterates over the input.

It reads the input one character at a time. If it sees anything other than a blank, it just prints the character it sees. If it sees a blank, it shifts to a different state. In that state, it prints one blank, and then doesn't print blanks if it sees them. Then, it continues reading the input, but ignores all blanks it sees--until it hits a character that isn't a blank, at which point it shifts back to the first state.

(This concept is called a finite state machine, by the way, and a lot of theoretical computer science work has gone into what they can and can't do. Wikipedia can tell you more, though in perhaps more complicated detail than you're looking for. ;))


Pseudo code

while c = getchar:
    if c is blank:
        c = getchar until c is not blank
        print blank
    print c

C

You can substitute use of isblank here if you desire. It is unspecified what characters contrive blank, or what blank value is to be printed in place of others.

After many points made by Matthew in the comments below, this version, and the one containing isblank are the same.

int c;
while ((c = getchar()) != EOF) {
    if (c == ' ') {
        while ((c = getchar()) == ' ');
        putchar(' ');
        if (c == EOF) break;
    }
    putchar(c);
}

Since relational operators in C produce integer values 1 or 0 (as explained earlier in the book), the logical expression "current character non-blank or previous character non-blank" can be simulated with integer arithmetic resulting in a shorter (if somewhat cryptic) code:

int c, p = EOF;
while ((c = getchar()) != EOF) {
    if ((c != ' ') + (p != ' ') > 0) putchar(c);
    p = c;
}

Variable p is initialized with EOF so that it has a valid non-blank value during the very first comparison.

Tags:

C