2

I've written a program which should count upper and lower letters and other signs but it counts anything but when I click Enter and then ^C (EOF). I don't know how to jump over it, hope somebody can help me somehow <3

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

int main()
{
  char ch;
  int uppers = 0, lowers = 0, others = 0;


  while((ch = getchar()) != EOF)
  {
    if(islower(ch))
      lowers++;

    else if(isupper(ch))
      uppers++;

    else
      others++;
  }

  printf("\n\nUpper letters - %d  Lower letters - %d   Others- %d", uppers, lowers, others);


  return 0;
}
ne0.exe
  • 23
  • 5
  • 3
    use ^D instead of ^C – Hitokiri May 29 '20 at 12:56
  • 3
    Also: `char ch;` --> `int ch;` – chux - Reinstate Monica May 29 '20 at 13:07
  • Can u explain why?:0 – ne0.exe May 29 '20 at 19:44
  • 1
    Because `EOF` is a macro defined as `(-1)`. If the character value saved into `ch` were `255`, it would be indistinguishable from `EOF` because with 8-bit data size it would be just another representation of `-1`. As you can see in [the docs](http://www.cplusplus.com/reference/cstdio/getchar/), the signature of `getchar` is `int getchar (void)` and not `char getchar (void)`, so a data loss occurs when assigning the `int` value to the `char` variable. – CherryDT May 30 '20 at 11:45
  • _Furthermore, depending on the system architecture, the default character type may even be _unsigned_. In that case, it's the opposite - instead of the risk of a `255`-valued character (for example the letter `ü` on my keyboard) becoming indistinguishable from `EOF` due to both being treated as `-1` inside the _signed_ `char`, storing the `EOF` (`-1`) result coming from a `getchar()` call that returned `EOF` into an _unsigned_ `char` variable would turn it into actual `255` due to the lack of space, so you'd end up comparing `255 == -1` which is never true. – CherryDT May 30 '20 at 11:53
  • For more details, see https://stackoverflow.com/questions/35356322/difference-between-int-and-char-in-getchar-fgetc-and-putchar-fputc – CherryDT May 30 '20 at 11:53

2 Answers2

5

Ctrl+C sends a SIGINT which normally just terminates your application.

What you need is Ctrl+D, which triggers EOF.

EDIT: Note that on Windows' default shell you may need Enter, Ctrl+Z, Enter (or F6) instead (though Ctrl+Z does something else entirely in Linux shells, sending a SIGSTOP). See this question.

You could also compare against 0xD instead of EOF to catch Enter, or maybe use 0x1B which will catch Esc. This way you avoid the weirdness of how to trigger the end-of-input on different platforms (unless you want to process an input stream).

Also take a look at this comment above as well as this answer which contain important additional info that I was missing!

CherryDT
  • 25,571
  • 5
  • 49
  • 74
1

CherryDt has already provided an appropriate answer.


But just to add to that, EOF is not a character but instead an end condition. It may be OS dependent. You can't rely on it to work the same manner in every environment. My suggest would be to use any character itself as a condition to terminate loop, rather than an condition which is environment dependent.

NOTE : The solution worked of ending the program with keys worked for me on Windows only when I included a fflush(stdin); after the getchar(). Probably, getchar() takes the input you give and leaves newline character \n in the input stream which was causing problem when I tried to terminate using ctrl+D or ctrl+Z or F6.

But once you include fflush(stdin), this would solve the problem and now the program ends successfully when I use the F6 on Windows. You can also try with above mentioned keys if this does not work for you.

Hope this helps some Windows users if the above answer wasn't working for them.

Abhishek Bhagate
  • 5,583
  • 3
  • 15
  • 32
  • I'm just beginning so can u be more specific about that fflush(stdin), where exactly should i include that? – ne0.exe May 29 '20 at 19:39
  • Use it anywhere in your `while()` loop outside if-else conditions. We just need to flush the new-line character that's in our input stream which may cause errors in terminating the program. You can include that just before your while loops ends so that when the next input is taken using `getchar()` a newline character in the input stream won't be there. – Abhishek Bhagate May 29 '20 at 19:44
  • @ne0.exe Try it and tell if it works. It worked for me using F6 key once I included the `fflush(stdin);`. – Abhishek Bhagate May 29 '20 at 19:46
  • gosh, the only thing changed is it doesn't even show printf only '^Z' at the end of inputed letters – ne0.exe May 29 '20 at 19:48
  • @ne0.exe Try F6 and then pressing Enter. – Abhishek Bhagate May 29 '20 at 19:49
  • just going to the new line – ne0.exe May 29 '20 at 19:50
  • @ne0.exe If nothing is working, you best bet is to use a character instead of an end condition as I mentioned in the start of my answer. This isn't reliable and won't work in every environment. It is working for me, not for you. If you want to make your program consistent, you should consider using a condition like `while((ch = getchar()) != '/')` if you want to use `/` as end key or any character of your choice. – Abhishek Bhagate May 29 '20 at 20:03