3

This problem is from K&R p. 20: Write a program to count blanks, tabs, and newlines.

Here's my attempt:

#include <stdio.h>

int main()
{
  int character, whitespace = 0;

  printf("Enter some text, and press Ctrl-d when you're done.\n\n");

  while((character = getchar() != EOF) {
    if(character == (' ' || '\n' || '\t')) {
      ++whitespace;
    }
  }

  printf("\nYour text contains %d spaces, tabs, and lines.\n", whitespace);

  return 0;
}

The program doesn't work. It always gives the answer 0 no matter how many spaces, tabs, and newlines the user text contains. Can anyone see the problem? There's one other strange thing: I have to press Ctrl-d twice for it to register. I have no idea why. Thanks!

James McNellis
  • 348,265
  • 75
  • 913
  • 977
Bill
  • 161
  • 1
  • 2
  • 5
  • 3
    Your `while` statement is missing a right parenthesis; this is probably a copy and paste error since you say the program compiles and runs. Make sure that the missing right parenthesis in your program is after `getchar()` and not after `EOF`; otherwise you will get incorrect results. – James McNellis Jul 10 '10 at 22:30
  • You probably have to press `Ctrl-d` twice because you don't hit enter after your input. The shell buffers your input until it sees a linefeed. – Lucas Jul 10 '10 at 22:45

6 Answers6

18
if(character == (' ' || '\n' || '\t'))

tests whether character is equal to the result of (' ' || '\n' || '\t') (the result of this is 1, indicating that the result of the || is true). You need to test it individually against each of the three possible values, e.g.,

if(character == ' ' || character == '\n' || character == '\t')
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 1
    Expanding - this is a case of an English shorthand that simply doesn't apply in most programming languages. `(a == b) || (a == c)` is not the same as `(a == (b || c))` - the latter is often a bug. Note that the semantics you're intending for `(b || c)` is building a list - in Python you could write IIRC `if a in [b, c, d] :`, but it's still not just a shorthand for the conditional expression you want. –  Jul 10 '10 at 22:47
3

One of the issues you might be hitting is your condition.

Try something like:

if (character == '\n' || character == ' ' || character == '\t') {
    ++ whitespace;
}
NG.
  • 22,560
  • 5
  • 55
  • 61
1

Parenthesis in your while statement is wrong, it should be

while( (character = getchar()) != EOF) 

You assigned to character the value of the test getchar() != EOF which is 1 for whatever character was really read.

Patrick Schlüter
  • 11,394
  • 1
  • 43
  • 48
1

the problem with your code is if(character == (' ' || '\n' || '\t')) statement. The statement (' ' || '\n' || '\t') is equivalent to 32 || 13 || 9 (each character replaced by it equivalent ASCII value) which is equal to 1 as any not zero thing is consider as true in C/C++, so effectively you are doing if(character == 1). Now I think you can fix the problem in your code.

Also books says to count blanks, tabs, and newlines separately and you are trying to count the total numbers, so do something like this.

if(character == ' ')
  ++blanks;

if(character == '\t')
  ++tabs;

if(character == '\n')
  ++newlines;

If you want a complete solution, here is one which i had written a long time back.

#include <stdio.h>

int main(void)
{
  int blanks, tabs, newlines;
  int c;


  blanks = 0;
  tabs = 0;
  newlines = 0;

  do {
      c = getchar();
      if(c == ' ') {
          ++blanks;
      }
      else if(c == '\t') {
         ++tabs;
      }
      else if(c == '\n') {
         ++newlines;
      }
  }
  while(c != EOF)

  printf("Blanks: %d\nTabs: %d\nLines: %d\n", blanks, tabs, newlines);
  return 0;
}
Lord Zsolt
  • 6,492
  • 9
  • 46
  • 76
Ravi Gupta
  • 6,258
  • 17
  • 56
  • 79
0

isspace will be available as a macro or function depending on your system and saves you having to second guess what might constitute whitespace in your environment. Strictly speaking, it may be all of the following characters on your system. GNU C certainly thinks so.

' '
    space
'\f'
    formfeed
'\n'
    newline
'\r'
    carriage return
'\t'
    horizontal tab
'\v'
    vertical tab

This is how you can do the test.

 #include <ctype.h>

  while((character = getchar() != EOF) {
    if (isspace(character)) whitespace++;
  }
bjg
  • 7,457
  • 1
  • 25
  • 21
  • This solves a different problem (it counts extra characters beyond the ones in the problem). -1 for not reading the standard documentation - `isspace` is defined to return true for **exactly** that set of characters, plus potentially others in locales other than the `C` locale (but never fewer). – R.. GitHub STOP HELPING ICE Jul 11 '10 at 05:08
  • While I agree it solves a different problem (a superset of the one asked) I don't see that as injurious to health but rather to be likely of some benefit to an ab initio C programmer - perhaps encouraging some thinking outside the problem posed. How you can conclude that my answer suggests that I didn't read the standard documentation is more curious. In fact, to be able to conclude that **something didn't happen** without evidence quite is intriguing. Perhaps you could elaborate on how you came to such a novel conclusion? -1 for crass argumentation I would suggest. – bjg Jul 16 '10 at 00:30
0

The examples above are technically correct. It prints the values only after an EOF (End Of File) indicator is called. However, I think there is a better explanation of this exercise (1.8), so let me purpose an alternative. The code below will print the new lines, tabs and blanks right after each new line.

#include <stdio.h>
#define EOL '\n'

/* Excercise 1.8 - K&R's book - 2nd edition. */
main()
{
    int c, newlines, tabs, blanks;

    newlines = 0;
    tabs = 0;
    blanks = 0;

    while ((c = getchar()) != EOF)
    {
        if (c == '\n')
            ++newlines;
        else if (c == '\t')
            ++tabs;
        else if (c == ' ')
            ++blanks;

        if (c == EOL) {
        printf("Lines: %d\nTabs: %d\nBlanks: %d\n", newlines, tabs, blanks);
        }
    }
}
Plar625
  • 75
  • 8