The C Programming Language, confusion when comparing solution of Exercise 1-9 to 1-12

Viewed 151

As a programming novice I have been trying to teach myself C to better understand computers using The C Programming Language (2nd Edition).

This site has been very helpful so far in troubleshooting problems but there is one problem I can't get my head around. It is my proposed solution to exercise 1-12 using my solution to 1-9 as a backdrop. I was wondering if anyone in this online community would kindly point out where I'm going wrong.

Exercise 1-9 asks you to "Write a program to copy its input to its output, replacing each string of one of more blanks by a single blank"

There are many ways to skin the proverbial cat here but the solution that reads most simply to me is this:

int c;

while((c = getchar()) != EOF)
  {
   if(c == ' ')
     {
        putchar(' ');
        while((c = getchar()) == ' ') // if there are subsequent blanks
        ; // do nothing
     }

   if(c != EOF)
    putchar(c);
  }

Now Exercise 1-12 is asking you to "Write a program that prints its input one word per line."

My first attempt was successful but an oversimplification of the problem.

int c;

while((c = getchar()) != EOF)
{  if(c == ' ')
     putchar('\n');

else
  putchar(c);
}

So I've tried to rectify this to accept a much wider range of inputs and here is the result

int c;

while((c = getchar()) != EOF)
 {
    if(c == ' ' || c == '\t' || c == '\n')
     {
      putchar('\n');
      while((c = getchar()) == ' ' || (c = getchar()) == '\t' || (c = getchar()) == '\n')
      ;
     }

    if(c != EOF)
     putchar(c);
 }

Now I know this is wrong when I run it and I have looked up online other very simple ways to solve the problem.

My issue here is that I don't understand why it doesn't work. To me if the solution to 1-9 works I don't understand why it fails when I take the same principle to 1-12. Anyone who could point this out would be appreciated!

4 Answers
while((c = getchar()) == ' ' || (c = getchar()) == '\t' || (c = getchar()) == '\n')
           ^                         ^                          ^

You're calling getchar() three times. Those calls read three characters, and you compare the first against space, second against \t and third against \n. (The calls are separated by ||, so there should be no issues with undefined sequencing.)

Instead, use temp variable:

int c;
do {
    c = getchar();
} while (c == ' ' || c == '\t' || c == '\n');

Using isspace() from ctype.h would probably be better too.

What you did was almost correct, but getchar() consumes one character of input on every invocation.

You could have written

while ((c = getchar()) == ' ' || c == '\t' || c == '\n')

because the || operator is processed left-to-right with so called sequence point in between;

though clearer is to move the initialization of c out of the loop condition.

Finally, using isspace this would consume any whitespace characters, with much less typing:

#include <ctype.h>

int c;
do {
   c = getchar();
} while (isspace(c));

It might be worth mentioning a sane and readable way to write this code without "assignment inside conditions", "most operators on a single line wins a price" or other such bad and dangerous habits picked up from that old book:

#include <stdio.h>
#include <ctype.h>

int main (void)
{
  while(1)
  {
    int c = getchar();
    if (isspace(c))
    {
      putchar('\n');       // at first space found, print line feed
      do
        c = getchar();
      while(isspace(c));   // discard any additional spaces
    }

    if(c == EOF)           // here c will not be a space, but possibly EOF
    {
      break;
    }

    putchar(c);
  }
  
  return 0;
}

If your char is not a space then you will try to get another char from the user instead of analyzing the one that was entered.

correct your while to call it only once:

while ((c = getchar()) == ' ' || c == '\t' || c == '\n')
Related