1

I'm a C beginner, I don't understand why this code is not working?

void main(){
    char userInput = "a";

    if(userInput == "a"){
        printf("a");
    } else printf("b");

    getch();
}

returning "b"

but this one is working

void main(){
    char userInput;

    if("a" == "a"){
        printf("a");
    } else printf("b");

    getch();
}

returning "a"

What is the difference?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Abhishek Pandey
  • 13,302
  • 8
  • 38
  • 68
  • 5
    `char userInput = "a";` your compiler should complain. – Sourav Ghosh Sep 24 '18 at 10:26
  • 1
    Hint: `userInput` is a single `char` not a collection of `char`s – CinCout Sep 24 '18 at 10:26
  • 1
    `"a"` is a pointer (memory address) to 2 bytes containing a `a` character and a null byte. `'a'` is a single byte variable. `char` is the type for character variable. If you `"a" == "a"` then you are comparing POINTERS, ie. memory addreses, which just so happens to be equal, as the compiler putted both `"a"` strings into the same memory address. – KamilCuk Sep 24 '18 at 10:28
  • 2
    Neither piece is guaranteed to "work". String literals may have unique addresses. `"a" == "a"` may well be false, AFAIK. – Petr Skocik Sep 24 '18 at 10:32
  • 2
    Possible duplicate of [How do I properly compare strings?](https://stackoverflow.com/questions/8004237/how-do-i-properly-compare-strings) – too honest for this site Sep 24 '18 at 11:16
  • @toohonestforthissite The first half of the question is absolutely a dupe, but the second part isn't. The answer boils down to compiler optimizations. – Lundin Sep 24 '18 at 11:22
  • @Lundin: Both parts are dupes. Actually the second part is what I linked, the first part is a typo (`char *`, then it's the same as the 2nd part). Both are C basics explained very early in the respective chapters of every beginner's C book. There is no need to go that deep into compiler details. It's UB for comparing pointers which don't point to/exactly past the same object. – too honest for this site Sep 24 '18 at 11:24
  • 1
    @toohonestforthissite Well, in this case the code _does_ compare two pointers pointing at the same object, by chance. – Lundin Sep 24 '18 at 11:27
  • @Lundin: No, they don't - by the language. The comparison succeeding is the outcome of the UB. /talking about compiler optimisations: the compiler could have replaced the whole condition by `1`). – too honest for this site Sep 24 '18 at 11:29
  • 1
    @toohonestforthissite No that's nonsense. You got it mixed up with pointer arithmetic on pointers that don't point at the same object, which is not applicable here. The language says, C17 6.5.9: Equality operators: "**Constraints** One of the following shall hold: ... - both operands are pointers to qualified or unqualified versions of compatible types;". There is no poorly-defined behavior anywhere - pointer comparisons are perfectly well-defined and explained in detail at C17 6.5.9 §6. – Lundin Sep 24 '18 at 11:40
  • @Lundin: Heck, I always forget about that. Sorry, yes, you are right. Looks like a flaw in the standard to allow ambigous comparisons like the above. But still 6.5.9p6 should apply: "Two pointers compare equal if and only if … both are pointers to the same object …". Unless you find a passage in the standard claiming identical string literals are the same object. If they just "can be", it would be ambigous and imo a flaw in the standard. I think this paragraph is quite sloppy anyway, e.g. with the last sentence. – too honest for this site Sep 24 '18 at 11:48
  • @KamilCuk: `"a"` is an array of 2 char. In the contexts used by the OP it is converted to a pointer. Pointers and arrays are different things. – pmg Sep 24 '18 at 12:35
  • regarding: `void main(){` The signature for `main()` ALWAYS has a return type of `int`, regardless of what visual studio allows – user3629249 Sep 26 '18 at 00:08
  • regarding: `char userInput = "a";` this is trying to stuff an array into a single character ( or the address of the array "a" into a single character. Suggest either: `char userInput[] = "a";` or `char *userInput = "a";`. The first initializes an array the second initializes a pointer to an array – user3629249 Sep 26 '18 at 00:14

6 Answers6

5

A literal represented like "a", is a string literal. The essential type is an array of chars, like char [size]. It is not a compatible type with char, so the assignment

char userInput = "a";

is not valid.

You want to use a character constant, you write something like

char userInput = 'a';

That said, if("a" == "a") seems to work in your case, but it does not do what you think it does. It does not compare the content, rather, it compares the base address (address of the first element) of the strings, and in your case, they seem to be the same. Your compiler, happens to use the same memory location for the identical string literals (optimization) - so you see a truthy result, but this is not guaranteed by the standard. A(ny) compiler is free to choose it's own memory allocation strategy, with or without optimization process.

Using gcc, if the -fno-merge-constants is used as compilation option, this condition is expected to evaluate to falsy.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
2

With char userInput = "a"; you're initializing userInput with a char* and not with the character 'a'. Same with the comparison, you're comparing a char with a char*.

For both the initialization and the comparison you have to use single quotes around the character,

void main(){
    char userInput = 'a';

    if(userInput == 'a'){
        printf("a");
    } else printf("b");

    getch();
}
Guillem Castro
  • 271
  • 1
  • 5
0

Quote chars with ' So

char userInput = 'a';

if(userInput == 'a'){
Peheje
  • 12,542
  • 1
  • 21
  • 30
0

Ignoring invalid syntax char userInput = "a" (I take it you meant char*), then the first case is obvious and a common FAQ: you aren't comparing the contents of the strings, but their addresses. See How do I properly compare strings?

The same problem happens when you do "a" == "a", you compare the address of the strings. These read-only "..." constants in C are formally called string literals.

There's a common optimization technique used by compilers, known as "string pooling". String pooling means that upon encountering the same string literal several times in the program, the compiler allocates only one of them.

So in your case "a" and "a" happened to be the very same memory address, because only one of the string literals was actually allocated. You can try to print the actual addresses where the string literals are allocated, and see that they are identical:

#include <stdio.h>

int main (void) 
{
  printf("%p %p", "a", "a");  

}
Lundin
  • 195,001
  • 40
  • 254
  • 396
0

Simplified answer: In C anything that goes inside double quotes is string, I.e sequence of chars terminated with null. Single quote is for single character.

Example :

char c = ‘a’ ;

char *str = “string”;
danglingpointer
  • 4,708
  • 3
  • 24
  • 42
0

"a" is a string literal, and not a character literal, which should be quoted with single quotes, as in 'a'.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31