0

Below you will find the code that I wrote. So far, this code is to check if the user entered a small letter or a larger letter by scanning the input from the user which is a character and passing it to a function to return either 1 or 0 depending this is letter is in caps or not. So, what I don't understand is why "please enter a letter 0" is printed. My best guess is because scanf stacked the null character and it is saved so it had to check if this letter is in caps or not as well. But if I am right, can you please tell me a way to avoid this problem from happening??? Thanks a lot in advance.

#include <stdio.h>
#include <stdlib.h>

char CapsCheck (char c)
{
    if (c >= 65 && c<= 90 )
        return 1;
    else
        return 0;
}

int main()
{
    char c;
    while (1)
    {
        printf("please enter a letter: ");
        scanf("%c",&c);
        printf("%d\n",CapsCheck(c));
    }

    return 0;
}

Output:

please enter a letter: C
1
please enter a letter: 0
please enter a letter:

I explained everything in the details section but you can ask me in the replies if you wanted any more inquiries. PS: I am using Code blocks.

Jason
  • 2,493
  • 2
  • 27
  • 27
  • `scanf("%c"` reads also the newline character (`'\n'`). Try `scanf(" %c", &c)`, which will skip leading whitespace characters. – M. Nejat Aydin Feb 20 '23 at 14:43
  • You can change the `"%c"` to `" %c"` to make `scanf` skip initial whitespace before reading a non-whitespace character. – Ian Abbott Feb 20 '23 at 14:46
  • Please don't post pictures of text. I fixed it for you THIS TIME (lol). I would get rid of `scanf`. It's temperamental as hell if you don't know all its pitfalls. If you just need a character, maybe try `getchar`? – Jason Feb 20 '23 at 14:47
  • Does this answer your question? [scanf ignoring, infinite loop](https://stackoverflow.com/questions/5285737/scanf-ignoring-infinite-loop) – Abderrahmene Rayene Mihoub Feb 20 '23 at 14:51
  • Side note: Instead of writing your own function `CapsCheck`, you can simply use the function [`isupper`](https://en.cppreference.com/w/c/string/byte/isupper) from the header file `ctype.h`. Using that function also has the advantage that it also works for other [locales](https://en.cppreference.com/w/c/locale/setlocale). – Andreas Wenzel Feb 20 '23 at 17:02

1 Answers1

2

The problem is related to one big misconception that students (and teachers) have: you expect the C language to know about "the keyboard".

There's no keyboard in the standard, nor any "screen" or "monitor". You only have files. So each operating system has it's version of a special file, which is the console, that works as an interface with your keyboard and screen.

Specifically, when you try to read from stdio (the call to scanf) the console asks you for a line of text. You entered

C↲

which is the sequence of two bytes: 67 and 10.

The first scanf reads 67, then it prints 1↲. Then you print please enter a letter: , a second scanf reads 10, then it prints 0↲. Then you print please enter a letter: .

You need to take care of what is left on stdio by the console processing.

And you should definitely check if your scanf managed to read a character, by comparing its return value to 1.

Edit

The return value of scanf is "Number of receiving arguments successfully assigned (which may be zero in case a matching failure occurred before the first receiving argument was assigned), or EOF if input failure occurs before the first receiving argument was assigned."

This is how you could do it:

#include <stdio.h>
#include <stdlib.h>

char CapsCheck (char c)
{
    if (c >= 65 && c <= 90 ) {
        return 1;
    }
    else {
        return 0;
    }
}

int main(void)
{
    char c;
    while (1)
    {
        printf("please enter a letter: ");
        int res = scanf("%c",&c);     // (Try to) Read
        if (res != 1) {               // Check
            break;                    // Exit if reading failed
        }
        printf("%d\n", CapsCheck(c)); // Use what was read
        
        // Skip everything that is in the current line
        while (1) {
            int x = fgetc(stdin);
            if (x == EOF || x == '\n') {
                break;
            }
        }
    }

    return 0;
}
Costantino Grana
  • 3,132
  • 1
  • 15
  • 35
  • can you explain the last part where you say comparing the return value of scanf to 1? Why is that useful and how it is done? Secondly, How to take care of what is left on stdio? by using fflush(stdin)? – Ahmed El-Shaer Feb 20 '23 at 18:53
  • @AhmedEl-Shaer Check the edited answer. Notice that `fflush(stdin)` is not defined in the standard. So, it *may* work in your system. – Costantino Grana Feb 24 '23 at 08:45