0

I have been trying to understand why this is not working properly for the past five hours.

The question explicitly asks for the use of switch() and no if-else (or of the likes) to count the number of words, lines, and characters in typed up text. And exit the program with Ctrl+D or Ctrl+Z.

Here, I deconstructed the counting by figuring different cases of whether the current typed input is whitespace or not, and from thereon, judging by the previous letter, whether it is justified to count it as an extra word, character, and/or line. ( input = punctuation, previous input= character --> add 1 to word count and 1 to character count ; if input = newline and previous input !=whitespace --> add one to line counter + one to word counter, etc.)

My code is the following:


int main() {
  int letter = 0, prev_letter = 0, num_char = 0, num_words = 0, num_lines = 0;

  printf("User, please provide any text you wish using letters, spaces, tabs, "
         "and enter. \n When done, enter Ctrl+D or Ctrl+Z on your keyboard.");

  while ((letter = getchar()) != 4 &&
         letter != 26) // In ASCII, Ctrl+D is 4, and Ctrl+Z is 26
  {
    switch (isspace(letter)) {
    case 0: // False = is not a whitespace
    {
      switch (
          isalpha(prev_letter)) // checking to see if alphanumeric input or not
      {
      case 1:
        switch (ispunct(letter)) {
        case 1:
          num_words++;
          num_char++; // Punctuation considered as characters in this particular
                      // sub-exercise.
          break;
        }
        break;

      case 0:
        num_char++;
        break; // All other cases are just another character added in this case
               // 0 (Not whitespace)
      }
    } break;

    case 1: {
      switch (letter) {

      case 9: // 9 =Horizontal tab
      {
        switch (isspace(prev_letter)) {
        case 0:
          num_words++; // Assuming if not whitespace, then punctuation or
                       // character.
          break;
        default:
          break;
        }

      } break;

      case 32: // 32 = Space
      {
        switch (isspace(prev_letter)) {
        case 0:
          num_words++; // Assuming if not whitespace, then punctuation or
                       // character.
          break;
        default:
          break;
        }

      } break;

      case 13: // 13 = Carriage return
      {
        switch (isspace(prev_letter)) {
        case 0:
          num_words++;
          num_lines++;
          break;
        default:
          num_lines++;
        }

      } break;

      case 10: // 13 = Line Feed
      {
        switch (isspace(prev_letter)) {
        case 0:
          num_words++;
          num_lines++;
          break;
        default:
          num_lines++;
        }

      } break;

      default:
        printf("Test2");
      }
    } break;

    default:
      break;
    }

    prev_letter = letter;
  }

  printf("Number of characters is: %d. \n", num_char);
  printf("Number of words is: %d. \n", num_words);
  printf("Number of lines is: %d. \n", num_lines);
  return 0;
}```



It seems like isalpha(), ispunct(), isalnum() are not feeding properly my cases.

I have tried breaking it down to individual cases but when inputting text with tabs, spaces, and alphanumeric inputs, it fails to count words, characters, and lines properly.

What am I not seeing properly? Any pointers greatly appreciated.
0___________
  • 60,014
  • 4
  • 34
  • 74
Marcus G.
  • 3
  • 2
  • 1
    The character classification functions return a nonzero value when their arguments are in the appropriate class, but there is no guarantee that they return exactly 1 in such cases. Instead of assuming that they do, you can use the `default` case in conjunction with defining a case for 0. – John Bollinger Nov 11 '22 at 22:39
  • 1
    However, I do have to say that using `switch` to simulate the forbidden `if` seems pretty cheesy to me. I suspect that the assignment anticipates that you will use `switch` together with cases for individual `char` values, rather than engaging the character classification functions. – John Bollinger Nov 11 '22 at 22:41
  • Note also that your loop criterion needs also to test for `EOF`. In fact, that might be the *only* thing it needs to test for, as Ctrl-D will cause `getchar()` to signal EOF on Linux and Mac, whereas Ctrl-Z will have that effect on Windows. Only if you have to support *both* of those on every platform would you need to test for them specifically. – John Bollinger Nov 11 '22 at 22:49
  • The only value returned from `isXXX()` functions that you can specifcally test for is `0`. So if you *must* use `switch()` than have `case 0:` ... `default:`. – Weather Vane Nov 11 '22 at 22:52

2 Answers2

0

isalpha and similar return zero if the parameter is not letter or not zero if it is.

Use if statement not switch to test the condition. Using switch for logical data is not logical or practical.

use functions and write your own implementations of those functions using switch ... case

Example (using GCC extension case ranges - to be portable you need to have separate case for every letter or digit [like in myispace])

int myisalpha(unsigned char x)
{
    switch(x)
    {
    case 'a' ... 'z':
    case 'A' ... 'Z':
        return 1;
    }
    return 0;
}

int myisdigit(unsigned char x)
{
    switch(x)
    {
    case '0' ... '9':
        return 1;
    }
    return 0;
}


int myisspace(unsigned char x)
{
    switch(x)
    {
    case ' ':
    case '\n':
    case '\r':
    case '\t':
    case '\v':
    case '\f':
        return 1;
    }
    return 0;
}
0___________
  • 60,014
  • 4
  • 34
  • 74
  • Thanks for the prompt answer! Unfortunately, I am obliged to only use switch(), as I have already covered the if-else version in another sub-exercise. Stupid question (I am new and doing my best): when it IS, the 'output' to isalpha() can be anything else than 0, and hence not always 1 correct? – Marcus G. Nov 11 '22 at 22:45
  • Yes — the return value from `isalpha()` is either 0 or non-zero; you cannot reliably predict what the non-zero value will be. If you must use a `switch` (it must be a course exercise; there is no reason to use a `switch` otherwise), then `switch (isalpha(prev_letter)) { case 0: /* … code for non-letters … */; break; default: /* … code for letters … */; break; }`. – Jonathan Leffler Nov 12 '22 at 01:48
0

That seems an odd assignment. Maybe you're misunderstanding it, but assuming you aren't, let me see if I can figure it out.

switch compares one variable to several values, so that would mean the first part is to determine a single value from several test functions.

A common use of switch is to check enum values, so you can start by defining an enum with the values you need. You're using isalpha(), ispunct(), and isspace() in your code, so I'll define those enum values.

enum chartype {
    IS_ALPHA,
    IS_PUNCT,
    IS_SPACE,
    IS_UNKNOWN
};

You can select an enum value without using if with the ? : operators.

enum chartype letter_chartype =
    isalpha(letter) ? IS_ALPHA
  : ispunct(letter) ? IS_PUNCT
  : isspace(letter) ? IS_SPACE
  : IS_UNKNOWN;

That lets you use a switch for each character type.

switch(letter_chartype) {
  case IS_ALPHA:
    ...
    break;
  case IS_PUNCT:
    ...
    break;
  case IS_SPACE:
    ...
    break;
  default:
    ...
    break;
}

That doesn't do your assignment for you, but I hope that helps give you some direction. I'm assuming you covered the ? : operators. If not, you might have to do something longer, trickier, or stupider (stupid often looks clever, be careful about that).

John Bayko
  • 746
  • 4
  • 7