I need to write a program that reads from the input a sentence terminated by a new line. The program should write an encryption of the sentence in a way that the letter 'a' is swapped with 'z', 'b' with 'y' and so on. I am not supposed to use arrays, that is why I can't find a solution for this problem.
This is my code:
#include<stdio.h>
int main() {
char alphabet, temp;
while( scanf("%c", &alphabet) != '\n') {
for(char i ='a', j='z'; i <= 'z', j>='a'; i++, j--) {
if(alphabet == i) {
temp = j;
}
}
printf("%c", temp);
}
return 0;
}
When I input: abc as an output I get zyxxxxxxxxxxxxxxxxxxxxxxxxx(an infinite number of x).
So to sum up:
Input:abc. Output: zyxxxxx(infinite number of x).
You messed up the return value of scanf:
while( scanf("%c", &alphabet) != '\n'){
You want to stop the loop when the entered character (in alphabet) is a line break.
But you test the return value of scanf which will never be '\n' as it returns the number of converted fields.
You could try like this:
while( scanf("%c", &alphabet) == 1 && alphabet != '\n'){
Compile your code with warnings enabled (e.g. Wall flag)! This:
for(char i ='a', j='z'; i <= 'z', j>='a'; i++, j--)
should give:
warning: left-hand operand of comma expression has no effect [-Wunused-value]
You need to use the logical AND operator && and not a comma between the two comparissons.
Moreover, use getchar() instead, like this:
#include<stdio.h>
int main() {
char temp;
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
for(char i ='a', j='z'; i <= 'z'&& j>='a'; i++, j--){
if(ch == i){
temp = j;
}
}
if(ch <= 'z'&& ch >= 'a') // do not print if 'ch' is a digit for example
printf("%c", temp);
}
return 0;
}
Output:
zyx
If you have to use scanf(), then try reading into alphabet, check the return value of scanf, and compare to newline, like this:
while(scanf("%c", &alphabet) != 0 && alphabet != '\n')
Related
I've encountered a problem when validating a single-char scanf input in C and I cannot find an existing solution that works...
The scenario is: a method is taking a single letter 'char' type input and then validating this input, if the criteria is not met, then pops an error message and re-enter, otherwise return this character value.
my code is:
char GetStuff(void)
{
char c;
scanf("%c", &c);
while(c != 'A' || c != 'P')
{
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%c", &dtChar);
}
return c;
}
however, i got the infinite loop of error message no matter what input I type in. I read some other posts and guess it's the problem that %c specifier does no automatically get rid of the newline when I hit enter, and so far I have tried:
putting a white space before/after %c like:
scanf(" %c", &c);
write a separate method or include in this GetStuff method to clean the newline like:
void cleanBuffer(){
int n;
while((n = getchar()) != EOF && n != '\n' );
}
Can anyone help me with this problem please? Thank you in advance.
Please consider the following snippet:
#include <stdio.h>
#include <ctype.h>
char GetStuff(void)
{
char c;
do {
printf("Please enter A for AM or P for PM: ");
scanf ("%c", &c);
// clean input buffer (till the end of line)
while(getchar()!='\n');
} while(toupper(c) != 'A' && toupper(c) != 'P');
return c;
}
int main(void)
{
printf("Your input is'%c'\n", GetStuff());
return 0;
}
Note the points:
condition while(c != 'A' || c != 'P') will be always true (just because one character cannot be 'A' and 'P' at the same time), so use while(c != 'A' && c != 'P') instead
No need for two scanf if you use do..while loop
After entering a char with scanf it is recommended to clean all characters from buffer, e.g. with while(getchar()!='\n'); (this will clean all input including incorrect and redundant characters)
use toupper to avoid making 4 comparison (actually single c=toupper(c) inside loop can minimize your while as while(c != 'A' && c != 'P') )
UPDATE:
To add message "Invalid input" and adding some other useful improvement subjected befor... new code is as:
#include <stdio.h>
#include <ctype.h>
void CleanBuffer(){
int n;
while((n = getchar()) != EOF && n != '\n' );
}
char GetStuff(void)
{
char c;
do {
printf("Please enter A for AM or P for PM: ");
scanf (" %c", &c);
c = toupper(c); // here letter become uppercase
CleanBuffer();
} while( (c != 'A' && c != 'P')?printf("Invalid input! "):0 );
return c;
}
int main(void)
{
printf("You have entered: %c\n", GetStuff());
return 0;
}
Note: function will return 'A' or 'P' in uppercase, so if this is not needed change the code as in example before update (use two toupper and do not change c after scanf). Also you can use tolower as an option (of course with comparing to 'a' and 'p').
#include <stdio.h>
char GetStuff(void) {
char c;
scanf("%c", &c);
getchar();
while ((c != 'A') && (c != 'a') && (c != 'P') && (c != 'p')) {
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%c", &c);
getchar();
}
return c;
}
int main(void) {
printf("Calling GetStuff()...\n");
char x = GetStuff();
printf("User entered %c\n", x);
return 0;
}
You are using while (c != 'A' || c != 'P') as your loop conditional, but this will always return true. What you meant to use is the && "and" operator, instead of the || "or" operator.
Also, call getchar() after your scanf statements, to capture the newline. This should work the way you want it to.
Inside loop you are taking input in dtChar but your loop condition checks variable c which is not updated in the loop, that is causing infinite loop
Also you would change your condition
while(c != 'A' || c != 'P')
to
while(c != 'A' && c != 'P')
If you want user to enter either 'A' or 'P'
Another possible solution. As others mentioned the condition was to be done with &&. Anyway the big problem is how to remove what's left on the console input line. Since the console works by lines, we remove everything up to the next '\n'. If the user already left something on the input line before calling GetStuff(), it would be useful to add a call to SkipRestOfTheLine() before the while loop.
In general I suggest to start with a while(1) loop, before making it nicer (such as in the cleanBuffer() you posted).
#include <stdlib.h>
#include <stdio.h>
void SkipRestOfTheLine(void)
{
while (1) {
int c = fgetc(stdin);
if (c == EOF || c == '\n')
break;
}
}
char GetStuff(void)
{
while (1) {
int c = fgetc(stdin);
if (c == EOF)
exit(EXIT_FAILURE); // Deal with this case in an appropriate way
if (c == 'A' || c == 'P')
return c;
printf("invalid input, enter again (A for AM or P for PM): ");
SkipRestOfTheLine();
}
}
int main(void)
{
char c = GetStuff();
return 0;
}
try this,
char GetStuff(void)
{
char c;
scanf("%c", &c);
while (((c != 'A') || (c != 'a')) && ((c != 'P') || (c != 'p'))==1)
{
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%c", &dtChar);
}
return c;
}
I hope this works, some time because of not given proper bracket it is stuck in the loop.
#include <stdio.h>
int main(){
char c;
do{
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%s", &c);
}while ((c != 'A') && (c != 'P'));
return 0;
}
Hey guys I'm starting to learn C, and I was asked to code a program specifically, a caesar cipher (so, the idea is to replace any letter in the message by a letter three positions down the alphabet.)
My implementation should read a line of text and then either performs encryption or decryption, depending on the first character read. If the first character is $, then I'm supposed to encrypt the rest of the line, and precede the output by the character ?. If the first character is ?, then I'm supposed to decrypt the rest of the line, and precede my output by the character $.
So for example: ?Wr eh, ru qrw wr eh
the output should be: $To be, or not to be
and vice versa.
So this is my code so far:
#include <stdio.h>
int main(void){
char code[100], ch;
int i;
scanf("%s", &code);
if(code[0] == '$'){
for(i = 0; code[i] != '\0'; ++i){
ch = code[i];
if(ch >= 'a' && ch <= 'z'){
ch = ch + 3;
if(ch > 'z'){
ch = ch - 'z' + 'a' - 1;
}
code[i] = ch;
}
else if(ch >= 'A' && ch <= 'Z'){
ch = ch + 3;
if(ch > 'Z'){
ch = ch - 'Z' + 'A' - 1;
}
code[i] = ch;
}
}
printf("?%s\n", code);
return 0;
}
}
But the problem is, it returns the first character and stops whenever there are space.
Like for example I enter: $To be it outputs to: ?$To
Can someone please help me figure out what I'm doing wrong?
Here's a sample using getchar() to get you started:
#include <stdio.h>
int main() {
int ch; // Either EOF or one of the chars in 0-255
while ((ch = getchar()) != EOF) {
if ('A' <= ch && ch <= 'Z') {
int offset = ch - 'A';
printf("%c", 'a' + offset);
} else {
printf("%c", ch);
}
}
}
Now, this code isn't perfect in a lot of ways, but it does demonstrate how to use getchar(). Every time getchar() is called, it fetches the next char from standard input and returns it as an int. That's because when the input is over, it returns the special value EOF, which is outside the range of char.
The while loop here is a common idiom. When execution reaches the loop, it first has to call getchar(), whose result is stored into ch. Then it checks whether ch is EOF. If not, then the loop processes the character that was read. Otherwise, it exits and the program ends.
The body of the loop prints every character it sees, while converting the uppercase letters to lowercase.
I'm learning c language and I hit a wall, if you would like to help me I appreciate (here is the ex: "Write a program that reads characters from the standard input to end-of-file. For each character, have the program report whether it is a letter. If it is a letter, also report its numerical location in the alphabet and -1 otherwise." btw is not homework).The problem is with the \n i don't know how to make it an exception. I'm new around here please let me know if I omitted something. Thank you for your help.
int main(void)
{
char ch;
int order;
printf("Enter letters and it will tell you the location in the alphabet.\n");
while ((ch = getchar()) != EOF)
{
printf("%c", ch);
if (ch >= 'A' && ch <= 'Z')
{
order = ch - 'A' + 1;
printf(" %d \n", order);
}
if (ch >= 'a' && ch <= 'z')
{
order = ch - 'a' + 1;
printf(" %d \n", order);
}
if (order != (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
{
if (ch == '\n');
else if (order != (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
printf(" -1 \n");
}
}
system("pause");
}
You are talking about an "exception" which can be interpreted in other ways in programming.
I understand that you want that '\n' be "excepted" in the set of nonalphabetical characters, that is, that it doesn't generate the error value -1.
Since you are using console to run the program, a sequence of character is going to be read till ENTER key is pressed, which generates the character \n. So, I'm not pretty sure that the while() condition you used, that compares against EOF, it's a good decision of yours.
I would put there directly the comparisson against '\n'.
while ((ch = getchar()) != '\n')
To inform if ch is a letter or not, we could use string literals. The following use of string assignment would deserve more explanation, but I will omit it. It's valid with string literals:
char *info;
if (order != -1)
info = "is a letter";
else
info = "is not a letter";
You are assuming an encoding where the letters are in contiguous increasing order (as in ASCII).
By assuming that, it's enough to work with uppercase or lowercase letters, since you are only interested in the position that the letter occupy in the alphabet. So, you can choose to work with uppercase, for example, in this way:
if (ch >= 'a' && ch <= 'z')
ch = (ch - 'a' + 'A');
The effect of that line of code is that ch is converted to uppercase, only if ch is a lowercase letter. Another kind of character is not affected.
As a consequence, from now on, you only have uppercase letters, or nonalphabetical characters.
Then it's easy to code the remaining part:
if (ch >= 'A' && ch <= 'Z')
order = ch - 'A' + 1; // It brings no. position of letter in alphabet
else
order = -1; // This is the erroneous case
A printf() at the end of the loop could bring all the information about the character:
printf(" %16s: %4d \n", info, order);
The resulting code is shorter in more clear:
#include <stdio.h>
int main(void) {
char ch;
int order;
char *info;
while ((ch = getchar()) != '\n') {
printf("%c",ch);
if (ch >= 'a' && ch <= 'z') /* Converting all to uppercase */
ch = (ch - 'a' + 'A');
if (ch >= 'A' && ch <= 'Z')
order = ch - 'A' + 1; /* Position of letter in alphabet */
else
order = -1; /* Not in alphabet */
if (order != -1)
info = "is a letter";
else
info = "is not a letter";
printf(" %16s: %4d \n", info, order);
}
}
If you need to end the input by comparing against EOF, then the type of ch has to be changed to int instead of char, so you can be sure that the EOF value (that is an int) is properly held in ch.
Finally, this means that ch needs initialization now, for example to a neutral value in the program, as '\n'.
Finally, just for fun, I add my super-short version:
#include <stdio.h>
int main(void) {
int ch, order;
while ((ch = getchar()) != '\n') {
order = (ch>='a' && ch<='z')? ch-'a'+1:((ch>='A' && ch<='Z')? ch-'A'+1: -1);
printf("%c %8s a letter: %4d \n", ch, (order != -1)? "is":"is not", order);
}
}
The C language does not have exceptions. Exceptions were first introduced into programming in C++. You can do it manually in C using setjmp() and longjmp(), but it really isn't worth it.
The two most popular of doing error handling in C are:
Invalid return value. If you can return -1 or some other invalid value from a function to indicate 'there was an error', do it. This of course doesn't work for all situations. If all possible return values are valid, such as in a function which multiplies two numbers, you cannot use this method. This is what you want to do here - simply return -1.
Set some global error flag, and remember to check it later. Avoid this when possible. This method ends up resulting in code that looks similar to exception code, but has some serious problems. With exceptions, you must explicitly ignore them if you don't want to handle the error (by swallowing the exception). Otherwise, your program will crash and you can figure out what is wrong. With a global error flag, however, you must remember to check for them; and if you don't, your program will do the wrong thing and you will have no idea why.
First of all, you need to define what you mean by "exception"; do you want your program to actually throw an exception when it sees a newline, or do you simply want to handle a newline as a special case? C does not provide structured exception handling (you can kind-of sort-of fake it with with setjmp/longjmp and signal/raise, but it's messy and a pain in the ass).
Secondly, you will want to read up on the following library functions:
isalpha
tolower
as they will make this a lot simpler; your code basically becomes:
if ( isalpha( ch ) )
{
// this is an alphabetic character
int lc = tolower( ch ); // convert to lower case (no-op if ch is already lower case)
order = lc - 'a' + 1;
}
else
{
// this is a non-alphabetic character
order = -1;
}
As for handling the newline, do you want to just not count it at all, or treat it like any other non-alphabetic character? If the former, just skip past it:
// non-alphabetic character
if ( ch == '\n' )
continue; // immediately goes back to beginning of loop
order = -1;
If the latter, then you don't really have to do anything special.
If you really want to raise an honest-to-God exception when you see a newline, you can do something like the following (I honestly do not recommend it, though):
#include <setjmp.h>
...
jmp_buf try;
if ( setjmp( try ) == 0 ) // "try" block
{
while ( (ch = getchar() ) != EOF )
{
...
if ( ch == '\n' )
longjmp( try, 1 ); // "throw"
}
}
else
{
// "catch" block
}
I'm having hard time trying to understand why you even try to handle '\n' specifically.
You might be trying to implement something like this:
int main(void)
{
char ch;
int order;
printf("Enter letters and it will tell you the location in the alphabet.\n");
while ((ch = getchar()) != EOF)
{
printf("%c", ch);
if (ch >= 'A' && ch <= 'Z') {
order = ch - 'A' + 1;
printf(" %d \n", order);
} else if (ch >= 'a' && ch <= 'z') {
order = ch - 'a' + 1;
printf(" %d \n", order);
} else if (ch == '\n') { } else {
printf(" -1 \n");
}
}
system("pause");
}
While this is a good solution, I would recommend rewriting it in a more optimal way:
int main(void)
{
char ch;
printf("Enter letters and it will tell you the location in the alphabet.\n");
while ((ch = getchar()) != EOF)
{
int order;
if (ch != '\n'){
if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {
order = ch & 11111B;
printf("Letter %d\n", order);
} else {
order = -1;
printf("Not letter: %d\n", order);
}
}
}
system("pause");
}
This way the program relies on specific way letters coded in ASCII
As part of my course, I have to learn C using Turbo C (unfortunately).
Our teacher asked us to make a piece of code that counts the number of characters, words and sentences in a paragraph (only using printf, getch() and a while loop.. he doesn't want us to use any other commands yet). Here is the code I wrote:
#include <stdio.h>
#include <conio.h>
void main(void)
{
clrscr();
int count = 0;
int words = 0;
int sentences = 0;
char ch;
while ((ch = getch()) != '\n')
{
printf("%c", ch);
while ((ch = getch()) != '.')
{
printf("%c", ch);
while ((ch = getch()) != ' ')
{
printf("%c", ch);
count++;
}
printf("%c", ch);
words++;
}
sentences++;
}
printf("The number of characters are %d", count);
printf("\nThe number of words are %d", words);
printf("\nThe number of sentences are %d", sentences);
getch();
}
It does work (counts the number of characters and words at least). However when I compile the code and check it out on the console window I can't get the program to stop running. It is supposed to end as soon as I input the enter key. Why is that?
Here you have the solution to your problem:
#include <stdio.h>
#include <conio.h>
void main(void)
{
clrscr();
int count = 0;
int words = 0;
int sentences = 0;
char ch;
ch = getch();
while (ch != '\n')
{
while (ch != '.' && ch != '\n')
{
while (ch != ' ' && ch != '\n' && ch != '.')
{
count++;
ch = getch();
printf("%c", ch);
}
words++;
while(ch == ' ') {
ch = getch();
printf("%c", ch);
}
}
sentences++;
while(ch == '.' && ch == ' ') {
ch = getch();
printf("%c", ch);
}
}
printf("The number of characters are %d", count);
printf("\nThe number of words are %d", words);
printf("\nThe number of sentences are %d", sentences);
getch();
}
The problem with your code is that the innermost while loop was consuming all the characters. Whenever you enter there and you type a dot or a newline it stays inside that loop because ch is different from a blank. However, when you exit from the innermost loop you risk to remain stuck at the second loop because ch will be a blank and so always different from '.' and '\n'. Since in my solution you only acquire a character in the innermost loop, in the other loops you need to "eat" the blank and the dot in order to go on with the other characters.
Checking these conditions in the two inner loops makes the code work.
Notice that I removed some of your prints.
Hope it helps.
Edit: I added the instructions to print what you type and a last check in the while loop after sentences++ to check the blank, otherwise it will count one word more.
int ch;
int flag;
while ((ch = getch()) != '\r'){
++count;
flag = 1;
while(flag && (ch == ' ' || ch == '.')){
++words;//no good E.g Contiguous space, Space at the beginning of the sentence
flag = 0;;
}
flag = 1;
while(flag && ch == '.'){
++sentences;
flag=0;
}
printf("%c", ch);
}
printf("\n");
I think the problem is because of your outer while loop's condition. It checks for a newline character '\n', as soon as it finds one the loop terminates. You can try to include your code in a while loop with the following condition
while((c=getchar())!=EOF)
this will stop taking input when the user presses Ctrl+z
Hope this helps..
You can implement with ease an if statement using while statement:
bool flag = true;
while(IF_COND && flag)
{
//DO SOMETHING
flag = false;
}
just plug it in a simple solution that uses if statements.
For example:
#include <stdio.h>
#include <conio.h>
void main(void)
{
int count = 0;
int words = 1;
int sentences = 1;
char ch;
bool if_flag;
while ((ch = getch()) != '\n')
{
count++;
if_flag = true;
while (ch==' ' && if_flag)
{
words++;
if_flag = false;
}
if_flag = true;
while (ch=='.' && if_flag)
{
sentences++;
if_flag = false;
}
}
printf("The number of characters are %d", count);
printf("\nThe number of words are %d", words);
printf("\nThe number of sentences are %d", sentences);
getch();
}
#include <stdio.h>
#include <ctype.h>
int main(void){
int sentence=0,characters =0,words =0,c=0,inside_word = 0,temp =0;
// while ((c = getchar()) != EOF)
while ((c = getchar()) != '\n') {
//a word is complete when we arrive at a space after we
// are inside a word or when we reach a full stop
while(c == '.'){
sentence++;
temp = c;
c = 0;
}
while (isalnum(c)) {
inside_word = 1;
characters++;
c =0;
}
while ((isspace(c) || temp == '.') && inside_word == 1){
words++;
inside_word = 0;
temp = 0;
c =0;
}
}
printf(" %d %d %d",characters,words,sentence);
return 0;
}
this should do it,
isalnum checks if the letter is alphanumeric, if its an alphabetical letter or a number, I dont expect random ascii characters in my sentences in this program.
isspace as the name says check for space
you need the ctype.h header for this. or you could add in
while(c == ' ') and whie((c>='a' && c<='z') || (c >= 'A' && c<='Z')
if you don't want to use isalpace and isalnum, your choice, but it will be less elegant :)
The trouble with your code is that you consume the characters in each of your loops.
a '\n' will be consumed either by the loop that scans for words of for sentences, so the outer loop will never see it.
Here is a possible solution to your problem:
int sentences = 0;
int words = 0;
int characters = 0;
int in_word = 0; // state of our parser
int ch;
do
{
int end_word = 1; // consider a word wil end by default
ch = getch();
characters++; // count characters
switch (ch)
{
case '.':
sentences++; // any dot is considered end of a sentence and a word
break;
case ' ': // a space is the end of a word
break;
default:
in_word = 1; // any non-space non-dot char is considered part of a word
end_word = 0; // cancel word ending
}
// handle word termination
if (in_word and end_word)
{
in_word = 0;
words++;
}
} while (ch != '\n');
A general approach to these parsing problems is to write a finite-state machine that will read one character at a time and react to all the possible transitions this character can trigger.
In this example, the machine has to remember if it is currently parsing a word, so that one new word is counted only the first time a terminating space or dot is encountered.
This piece of code uses a switch for concision. You can replace it with an if...else if sequence to please your teacher :).
If your teacher forced you to use only while loops, then your teacher has done a stupid thing. The equivalent code without other conditional expressions will be heavier, less understandable and redundant.
Since some people seem to think it's important, here is one possible solution:
int sentences = 0;
int words = 0;
int characters = 0;
int in_word = 0; // state of our parser
int ch;
// read initial character
ch = getch();
// do it with only while loops
while (ch != '\n')
{
// count characters
characters++;
// count words
while (in_word)
{
in_word = 0;
words++;
}
// skip spaces
while (ch == ' ')
{
ch = -1;
}
// detect sentences
while (ch == '.')
{
sentences++;
ch = -1;
}
// detect words
while ((ch != '\n')
{
word_detected = 1;
ch = -1;
}
// read next character
ch = getch();
}
Basically you can replace if (c== xxx) ... with while (c== xxx) { c = -1; ... }, which is an artifical, contrieved way of programming.
An exercise should not promote stupid ways of doing things, IMHO.
That's why I suspect you misunderstood what the teacher asked.
Obviously if you can use while loops you can also use if statements.
Trying to do this exercise with only while loops is futile and results in something that as little or nothing to do with real parser code.
All these solutions are incorrect. The only way you can solve this is by creating an AI program that uses Natural Language Processing which is not very easy to do.
Input:
"This is a paragraph about the Turing machine. Dr. Allan Turing invented the Turing Machine. It solved a problem that has a .1% change of being solved."
Checkout OpenNLP
https://sourceforge.net/projects/opennlp/
http://opennlp.apache.org/
I'm doing a program that is asking the user to enter a stream of characters and printing out the number of uppercase and lowercase letters. I'm trying to do it with a function, but having some trouble printing it..for every character input im entering im getting 0, 0
Would appreciate your help to understand what am I doing wrong:
#include <stdio.h>
#include <ctype.h>
int case_letters(int ch);
int main(void)
{
int x;
printf("please enter a some characters, and ctrl + d to see result\n");
case_letters(x);
return 0;
}
int case_letters(int ch)
{
int numOfUpper = 0;
int numOfLower = 0;
while ((ch = getchar()) != EOF)
{
if ((ch = isdigit(ch)) || ch == '\n')
{
printf("please enter a valid character\n");
continue;
}
else if ((ch = isupper(ch)))
{
numOfUpper++;
}
else if ((ch = islower(ch)))
{
numOfLower++;
}
}
return printf("%d, %d", numOfUpper, numOfLower);
}
All of your if statements assign different value to ch and do not check ch's value.
For example, if you enter a correct char, this
if ((ch = isdigit(ch)) || ch == '\n')
will assign 0 to ch, because isdigit(ch) will return 0. I guess you need
if ( isdigit(ch) || ch == '\n')
Same for islower and isupper.
if ((ch = isdigit(ch)) || ch == '\n')
^-- assignment, not equality test.
You're trashing the value of ch with the return value of isdigit(), and isupper(), and islower(), so that the original user-entered value is destroyed as soon as you do the isdigit test.
Try
if (isdigit(ch) || ch == '\n')
else if (isupper(ch))
else if (islower(ch))
instead. No need to preserve the iswhatever values.