112
void main() {
    if("a" == "a")
      printf("Yes, equal");  
    else
      printf("No, not equal");
}

Why is the output No, not equal?

moinudin
  • 134,091
  • 45
  • 190
  • 216
Javed Akram
  • 15,024
  • 26
  • 81
  • 118
  • 101
    `void main` ??? Ew... – Paul R Jan 30 '11 at 15:59
  • 5
    @Paul: In the newest [draft](http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf) I read under `5.1.2.2.1 §1`: "[...] It shall be defined with a return type of int and with no parameters `int main(void) { /* ... */ }` or with two parameters[...] ; or in some other implementation-defined manner." Wouldn't that mean, that an implementation may define it as `void main`? – Lucas Jan 30 '11 at 17:20
  • 48
    Embedded C compilers allow void main() because there may not be any operating system to give a return code to. – Jeanne Pindar Jan 30 '11 at 20:20
  • @Lucas: that's the reason why should use `int main(void)`, actually. – Bastien Léonard Jan 30 '11 at 23:31
  • 1
    @Paul - Believe it or not, some embedded libraries still assume signal handlers to be of type `int` (because the underlying main() never returns control to an underlying OS). It's not uncommon to find non hosted (or even hosted) implementations where main never returns. – Tim Post Jan 31 '11 at 00:57
  • 26
    How can a question like this get upvoted so often? It's really not that interesting ... I mean, that strings are arrays and arrays are pointers is really an old hat in C, isn't it? – Felix Dombek Jan 31 '11 at 02:27
  • 65
    @Felix, it's a concisely-written question that address a common point of confusion for newcomers to the language. SO isn't for experts only - it's for beginners as well, and targeted questions like this are good for referring beginners to in the future. – bdonlan Jan 31 '11 at 03:00
  • I remember the first hello world I ever wrote in C was a void main (). but I have a even better question, Why are people so focused on this detail ? the question isn't about the structure of the main !!! if you want to be picky, shouldn't there be an include for the use of printf ? – Jason Rogers Jan 31 '11 at 06:42
  • 6
    @Jason - We're programmers. We have to be nitpicky. Otherwise the compiler beats us. – Chris Lutz Jan 31 '11 at 11:37
  • 8
    @Felix: Except arrays *aren't* pointers... – GManNickG Jan 31 '11 at 19:43
  • 1
    @GMan: If they are on the heap, of course they are. They data type is exactly the same. – Felix Dombek Jan 31 '11 at 20:19
  • 1
    @Gman, please, if you're so smart, you might as well explain how they are different. If I say `char *a;` I am declaring a pointer -- whether this is an array with one or multiple elements does not matter. – Felix Dombek Jan 31 '11 at 20:26
  • 1
    @Gman: I think I get what you mean. It's just a different way of looking at it and doesn't make my statement wrong. You say an array is *the physical memory where the data in the array lies* and a pointer is *the physical memory where the beginning of the array is stored*. I say, if you want an array, you declare a pointer. If you want to pass an array, you pass a pointer. You can do `a[0]` just to access something which is "not an array" according to your logic. Therefore, I'll stick at my position -- it's how my professors explain it in university and how I understand it. – Felix Dombek Jan 31 '11 at 20:35
  • 37
    @Felix: You are wrong. **arrays are not pointers** – John Dibling Jan 31 '11 at 20:52
  • 4
    @Felix: A pointer points to a location, whether that location has something in it or not. A pointer does not guarantee the existence of an array of any size whatsoever at the location it points to. I can write an address down for a house but it doesn't make the house exist. – Jeff Yates Feb 01 '11 at 15:47
  • 1
    @GMan, @John, @Jeff: I've read the relevant questions on SO and conclude: They are not the same, but arrays are converted to pointers in most cases so the observed behaviour is generally the same unless you use `sizeof` or one or two other constructs which exhibit the internal difference. Is this correct now? – Felix Dombek Feb 01 '11 at 18:03
  • 9
    I think it's funny how everybody points out that 'arrays are not pointers' but nobody cares to actually explain the difference. – Jakob Egger Feb 20 '12 at 13:39
  • The general way I regard arrays is "hey, a pointer!" because in a lot of simple situations, it's practical and easy to use pointers as arrays and arrays as pointers. Of course, technically speaking, it's not true that arrays are pointers, but you can mostly use them interchangeably. There are cases when not - but IMHO it's better to keep these exceptions (such as sizeof, etc.) in mind and consider arrays being compatible with pointers than always being nitpicky about what the types and arrays and pointers and whatever else are. If this wasn't the case, they wouldn't be compatible... –  Sep 06 '12 at 21:17
  • @JakobEgger can you explain me the difference ? – mf_ Jun 02 '13 at 18:26
  • 1
    @mf_ The only difference I am aware of is that they behave differently when using sizeof. For example, on my system, `sizeof(int[5])` is 20 (5 times `sizeof(int)`), while `sizeof(int*)` is 8. But there's a nasty exception: arrays in function arguments *are* pointers! – Jakob Egger Jun 06 '13 at 12:05
  • 3
    Section 6 of the [comp.lang.c FAQ](http://www.c-faq.com) explains the (admittedly confusing) relationship between arrays and pointers. – Keith Thompson Apr 11 '14 at 18:55
  • @JakobEgger: There are other differences. For example, `struct A { int arr[50]; }` and `struct B { int* arr; }`. Assigning members of `struct A` will copy the contents of the array; assigning members of `struct B` will not (since the pointer might not point to an array at all!). – Tim Čas Feb 12 '15 at 21:02

11 Answers11

211

What you are comparing are the two memory addresses for the different strings, which are stored in different locations. Doing so essentially looks like this:

if(0x00403064 == 0x002D316A) // Two memory locations
{
    printf("Yes, equal");
}

Use the following code to compare two string values:

#include <string.h>

...

if(strcmp("a", "a") == 0)
{
    // Equal
}

Additionally, "a" == "a" may indeed return true, depending on your compiler, which may combine equal strings at compile time into one to save space.

When you're comparing two character values (which are not pointers), it is a numeric comparison. For example:

'a' == 'a' // always true
  • 12
    GCC also has the options `-fmerge-constants` and `-fno-merge-constants` to enable/disable string and floating-point constant merging across translation units, though on some GCCs it seems that constant merging is always enabled regardless of that option. – Adam Rosenfield Jan 30 '11 at 15:35
  • 2
    It would work if you use 'a' instead of "a". The first is a char, which is actually a numeric value. – GolezTrol Jan 30 '11 at 15:41
  • @GolezTrol: in C, the literal 'a' actually has `int` type. :-) Also, pointers don't have to be numeric values. – Bastien Léonard Jan 30 '11 at 16:25
  • `int` is numeric too, isn't it? But I thought chars were Byte. Int is 4 bytes. Pointers themselves are integer as well. They contain the address of a bunch of data (data that indeed doesn't have to be numeric). – GolezTrol Jan 30 '11 at 16:58
  • `'a' == 'A' // not true` ... MySQL begs to differ. – Steven Jan 30 '11 at 21:09
  • @Steven: MySQL does string comparsion based on the collation of the table. That has little relevance to C, but if you want similar locale-dependent string comparison in C (when comparing strings) use `strcasecmp` (specified by POSIX, but not by ANSI C). – Ken Bloom Jan 31 '11 at 00:43
  • as time cooper pointed out you want to compare the content of your string and not the pointers to those Strings. its a frequent error. what I find interesting is that C doesn't necessarily optimize the storage of static strings such as "a" – Jason Rogers Jan 31 '11 at 06:45
  • @Adam: due to my curiosity, I *had* to try those flags and have to report that they don't have any influence on the primitive test code in the question. Probably because `-fmerge-constants` is documented to "[..] merge identical constants [..] across compilation units". The merging *within* a compilation unit is probably always-on. – Joachim Sauer Jan 31 '11 at 12:46
  • @Joachim Sauer: Yes, I got the same results. Even across translation units, the flag doesn't seem to have any effect -- with the several different versions of GCC that I tried, constant merging across translation units seems to be either always-on or always-off, regardless of that flag. – Adam Rosenfield Jan 31 '11 at 17:20
  • Can someone please help me understand how does it compare address not the strings? I thought that he was trying to compare the strings which is not directly possible as he did. –  Jul 01 '11 at 23:35
  • I don't get the same error. It says true for me -- http://ideone.com/rqf0O2#view_edit_box – David G Dec 16 '12 at 13:13
  • @David: `Additionally, "a" == "a" may indeed return true, depending on your compiler, which may combine equal strings at compile time into one to save space.` –  Dec 16 '12 at 13:15
52

I'm a bit late to the party, but I'm going to answer anyway; technically the same bits, but from a bit different perspective (C parlance below):

In C, the expression "a" denotes a string literal, which is a static unnamed array of const char, with a length of two - the array consists of characters 'a' and '\0' - the terminating null character signals the end of the string.

However, in C, the same way you cannot pass arrays to functions by value - or assign values to them (after initialization) - there is no overloaded operator == for arrays, so it's not possible to compare them directly. Consider

int a1[] = {1, 2, 3};
int a2[] = {3, 4, 5};
a1 == a2 // is this meaningful? Yes and no; it *does* compare the arrays for
         // "identity", but not for their values. In this case the result
         // is always false, because the arrays (a1 and a2) are distinct objects

If the == is not comparing arrays, what does it actually do, then? In C, in almost all contexts - including this one - arrays decay into pointers (that point to the first element of the array) - and comparing pointers for equality does what you'd expect. So effectively, when doing this

"a" == "a"

you are actually comparing the addresses of first characters in two unnamed arrays. According to the C standard, the comparison may yield either true or false (i.e. 1 or 0) - "a"s may actually denote the same array or two completely unrelated arrays. In technical terms, the resulting value is unspecified, meaning that the comparison is allowed (i.e. it's not undefined behavior or a syntax error), but either value is valid and the implementation (your compiler) is not required to document what will actually happen.

As others have pointed out, to compare "c strings" (i.e. strings terminated with a null character) you use the convenience function strcmp found in standard header file string.h. The function has a return value of 0 for equal strings; it's considered good practice to explicitly compare the return value to 0 instead of using the operator `!´, i.e.

strcmp(str1, str2) == 0 // instead of !strcmp(str1, str2)
eq-
  • 9,986
  • 36
  • 38
47

According in C99(Section 6.4.5/6)

String Literals

It is unspecified whether these arrays are distinct provided their elements have the appropriate values.

So in this case it is unspecified whether both "a"s are distinct. An optimized compiler could keep a single "a" in the read-only location and both the references could refer to that.

Check out the output on gcc here

Community
  • 1
  • 1
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
19

Because they are 2 separate const char*'s, pointers, no actual values. You are saying something like 0x019181217 == 0x0089178216 which of course returns NO

Use strcmp() instead of ==

SilentGhost
  • 307,395
  • 66
  • 306
  • 293
Antwan van Houdt
  • 6,989
  • 1
  • 29
  • 52
9

Simply put, C has no built-in string comparison operator. It cannot compare strings this way.

Instead, strings are compared using standard library routines such as strcmp() or by writing code to loop through each character in the string.

In C, a string of text in double quotes returns a pointer to the string. Your example is comparing the pointers, and apparently your two versions of the string exist at different addresses.

But it is not comparing the strings themselves, as you seem to expect.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
3

Pointers.

The first "a" is a pointer to a null-terminated ASCII string.

The second "a" is a pointer to another null-terminated ASCII string.

If you're using a 32-bit compiler, I'd expect "a"=="a"-4. I've just tried it with tcc/Win32 though, and I get "a"=="a"-2. Oh well...

Lesmana
  • 25,663
  • 9
  • 82
  • 87
Nico57
  • 31
  • 1
  • 6
    Why would you expect strings to be aligned to 4-byte boundary? They aren't ints. 2 is what I'd expect (if the compiler doesn't merge them), since each string is two bytes long, including the null terminator. – Sergei Tachenov Jan 30 '11 at 15:52
  • Some degree of alignment may, for instance, allow `strcmp` to run several bytes at a time. Some compilers do it, some don't, some do it only for strings longer than some minimum... – zwol Jan 30 '11 at 23:00
  • @Zack: how would they know the length of the string before actually comparing them? – Joachim Sauer Jan 31 '11 at 13:14
  • I meant, some compilers align strings longer than some minimum. – zwol Jan 31 '11 at 15:55
1

this question sets very good trail of explanation for all the beginers....
let me also contribute to it.....

as everybody above explained about , why you getting such output.

now if you want your prog. To print "yes equal" then

either use

if(strcmp("a", "a") == 0)
{

}

or
do not use "a" as strings, use them as characters....

if('a'=='a')  
{  
printf ("yes Equal");  
}  

in C characters are 1 byte short integer.......

Lesmana
  • 25,663
  • 9
  • 82
  • 87
N-JOY
  • 10,344
  • 7
  • 51
  • 69
  • Characters occupy only 1 byte, but character literals, such as `'a'`, are actually integers. – Spidey Jun 20 '13 at 13:49
1

You're comparing two memory address, so the result is not always going to be true. Did you try if('a' == 'a'){...}?

Ken
  • 30,811
  • 34
  • 116
  • 155
0

if comparision between character is always in single quote, e.g.

if('a' == 'a')

and C can't support string comparision like "abc" == "abc"

It's done with strcmp("abc","abc")

Tisho
  • 8,320
  • 6
  • 44
  • 52
Bhavin
  • 240
  • 7
  • 19
0

Some compilers have 'merge strings' option that you can use to force all constant strings to have the same address. If you would use that, "a" == "a" would be true.

Daniel Mošmondor
  • 19,718
  • 12
  • 58
  • 99
-5

This guy does not use variables. Instead, he uses temporarily text arrays: a and a. The reason why

void main() 
{
    if("a" == "a")
      printf("Yes, equal");  
    else
      printf("No, not equal");
}

does not work of course, is that you do not compare variables.
If you would create variables like:

char* text = "a";
char* text2 = "a";

then you could compare text with text2, and it should be true

Maybe you shouldn't forget to use { and } =)

void main() {
    if("a" == "a")
    {
      printf("Yes, equal");
    }
    else
    {
      printf("No, not equal");
    }
}
Coding Mash
  • 3,338
  • 5
  • 24
  • 45
D. Ace
  • 1
  • 1
    "_and it should be __true___" -- No. It is *unspecified* whether the string literals will be stored in the same memory location. Read the other answers. – Spikatrix Mar 05 '16 at 10:56