-3

I wrote the following C program:

#include <stdio.h>

int main()
{
    char d;
    char e;
    printf("Babanin adini gir. \n");
    scanf("%s", &d);
    printf("Ananin adini gir. \n");
    scanf("%s", &e);
    printf("Senin adin %c ya da %c", d, e);
return 0;

}

It works perfectly fine in online C compiler but not in my VSCode or Codeblocks, it only says

Gimme a letter. 
s
Gimme another letter. 
a
Your letter is  or a

like that, it doesn't read the first letter or print it. Why is that?

blackbrandt
  • 2,010
  • 1
  • 15
  • 32
Horatioud
  • 1
  • 3
  • Cannot duplicate with [onlinegdb](https://www.onlinegdb.com/online_c_compiler) – blackbrandt Aug 11 '21 at 21:49
  • 5
    `%s` is for a string. A single `char` variable cannot hold anything except an empty string. Attempting to store a non-empty string into such a variable results in buffer overflow and Undefined Behaviour. Use `%c` for a single char or make the variable an appropriately sized char array. – kaylum Aug 11 '21 at 21:52
  • @blackbrandt I'm sorry but I didn't understand what you mean. – Horatioud Aug 11 '21 at 21:55
  • Horatio I was indicating that I could not duplicate the issue with that online compiler. That way, other users don't have to waste time seeing if it can be duplicated there. One of the first things anyone will do here is paste your code, run it, and see if the same issue occurs. – blackbrandt Aug 11 '21 at 21:58
  • 1
    @blackbrandt for a more tricky problem that would be true, but the first thing any experienced C coder will do with this is see the incorrect use of `scanf`, and there is no point wasting time trying to reproduce undefined behaviour – M.M Aug 11 '21 at 22:08

2 Answers2

2

When you say char d;, you tell the compiler to reserve exactly one byte of memory to hold one character.

Then when you say char e;, you tell the compiler to reserve exactly one byte of memory to hold another character.

Then you say scanf("%s", &d); which has the compiler read an entire string (including the string terminator) and try to store it in the one byte of memory reserved by char d;

The character you type when you run the program takes one byte of space and the string terminator takes another one so now you are storing two bytes of data in a spot only big enough for one byte.

And then you do it again for the second scanf call.

So now you have accessed memory you didn't reserve - you could have written over something really important. It is undefined behaviour and ANYTHING can happen (including making the program look as if it is working)

So, if you want to use char variables like you are now, the scanf("%s", &d); should be scanf(" %c", &d); and the other scanf call should be changed the same way.

The reason the scanf format string needs to start with a space is to tell the scanf function that it should ignore whitespace (like the newline that is created by pressing the enter key). Without that space, the second scanf will store a newline as its character because that is the second character that was input.

You might think that you could also change the variables to char d[2]; and char e[2]; so there is room to store the character and the string terminator. But this is a bad idea because, if the user enters more than one character before they press enter, you will still write past the end of the memory. So it has the exact same problem.

Another thing you could do (as suggested in the comments) is to not use scanf at all for reading single characters. If your variable is char d; then you could use d = getchar(); and that would work well - but you still need to do something to handle the newline character that comes in as the second character. That's why I think scanf(" %c", &d); is a good, simple way to make it work.

One other thing to note: you should always check the return value of the functions you call. If reading input doesn't work you should tell the user that the input is invalid and then not produce invalid output.

Jerry Jeremiah
  • 9,045
  • 2
  • 23
  • 32
  • 1
    When I say ANYTHING I really mean it - even time travel: https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633 – Jerry Jeremiah Aug 11 '21 at 21:58
  • Why would you not use `getchar` instead? – blackbrandt Aug 11 '21 at 22:00
  • 1
    @blackbrandt You're right. But making the minimum necessary change to fix it means the OP will understand why the change is necessary and understand why it fixes the problem. So `getchar()` might be a better answer but the OP will eventually need to understand why his scanf attempt didn't work. – Jerry Jeremiah Aug 11 '21 at 22:04
  • Okay! Thanks for the explanation. – blackbrandt Aug 11 '21 at 22:05
  • YeS, thanks, think started to understand how these storing works. making them all "%c" not entirely but almost fixed them all, had to use a blank space before %c to make it work. Thank you so much. – Horatioud Aug 11 '21 at 22:11
  • @Horatioud I noticed that just after I posted the answer and was just editing the question to mention that. I shouldn't have posted the answer without it... – Jerry Jeremiah Aug 11 '21 at 22:21
0

The answer by Jerry Jeremiah is good but I just wanted to add that if his solution doesn't work for you, you may want to use " %c" (with a leading space) instead of "%c" or the second scanf will get a newline instead of the second letter.

Refer to this thread: How to do scanf for single char in C

Tomasz Kalisiak
  • 101
  • 2
  • 7
  • 1
    Yes, as you said it didnt entirely work Jerry's so I had to use a blank space to make it work, thanks: – Horatioud Aug 11 '21 at 22:10