-1

I cannot understand this behaviour of the == operator:

char s1[4];
s1[0] = 'a';
s1[1] = 'a';
s1[2] = 'a';
s1[3] = '\0';

char *s2 = "aaa";
char *s3 = "aaa";

printf("s1: %s\n", s1); // aaa
printf("s2: %s\n", s2); // aaa
printf("s3: %s\n", s3); // aaa
printf("s1 == s2: %d\n", (s1 == s2)); // 0
printf("s1 == s3: %d\n", (s1 == s3)); // 0
printf("s2 == s3: %d\n", (s2 == s3)); // 1

The literal value of all 3 strings is the same (aaa), so why is the comparison successful only between s2 and s3 and not between s1 and s2? Clearly they all have different memory locations so that cannot account for the result.

Thanks

nourdine
  • 7,407
  • 10
  • 46
  • 58
  • 2
    If it compared string content then you would not need strcmp(). It works by accident when the compiler is smart about string literals. They often are, it merely requires support for a symbol table, a feature that any compiler needs anyway. And important, it can blow up pretty badly when a literal is used in a macro. – Hans Passant Jan 01 '18 at 13:08
  • 2
    They don't clearly have different memory locations. If you wanted to test that, you could have printed their addresses and perhaps seen that the compiler likely saw fit to use point you to the same address for s2 and s3 as the string literal is a constant and keeping more than one copy of the exact same literal would be an inefficient use of memory. – Christian Gibbons Jan 01 '18 at 14:58

4 Answers4

3

In expressions array designators are implicitly converted to pointers to their first elements.

From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)

3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

String literals have types of character arrays. From the C Standard (6.4.5 String literals)

6 In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals.78) The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence...

So for example in this expression

s2 == s3

there are compared addresses of the first characters of two string literals.

Moreover if to write for example

"aaa" == "aaa"

then the expression can yield either 1 or 0 depending on compiler options because according to the C Standard (6.4.5 String literals)

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

If you want to compare string literals as arrays instead of comparing addresses of their first characters you should use standard C function strcmp declared in the header <string.h>

For example

#include <string.h>

//...

printf("s1 == s2: %d\n", strcmp( s1, s2 ) == 0 ); 
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

The comparison compares memory addresses, not string contents (use strcmp() fr that). But

char *s2 = "aaa";

creates a read only string. It is not const char * to avoid breaking old code/.

char s1[] = "aaa";

or

char s1[4]; /* etc, initialise by hand */

creates a string in read / write memory. So in the first case, the compiler realises it can merge two identical strings.

Malcolm McLean
  • 6,258
  • 1
  • 17
  • 18
  • So basically the rule is to always always always use `strcmp` and forget about `==` when it comes to strings. Is that it? – nourdine Jan 01 '18 at 13:14
  • 1
    @nourdine: Yes. `==` simply isn’t defined for comparing array contents, and strings are stored as character arrays. – John Bode Jan 01 '18 at 14:01
0

This will compare the value of the pointers. in other words, the memory locations.

The proper way to compare strings is using the library function strcmp:

  if(strcmp(s1, s2) == 0) { printf("The strings are the same."); }

One of the risks with your code is that you have set the pointers equal to a static string. Even though you have written these as two separate strings, the compiler could easily optimize this away to a single string. This would give you two pointers to the same memory location, which will make these appear to be equal even though they are supposed to be different strings in your logic.

David Hoelzer
  • 15,862
  • 4
  • 48
  • 67
  • I know this is a stupid question before I ask it but I will ask it anyway: I suppose this mechanism only applies to strings right? I mean, numbers and chars are literally compared by the compiler, aren't they? Regardless of where they are stored in memory. Thanks – nourdine Jan 01 '18 at 13:33
  • That is correct. – David Hoelzer Jan 01 '18 at 14:49
  • Something's not right when the accepted answer has the lowest vote count. :) – David Hoelzer Jan 01 '18 at 21:45
0

The literal value of all 3 strings is the same

No - there are not 3 strings.

s1 is an array whose contents forms a string.

s2, s3 are pointers. The 2 pointers, in this case, happen to be initialized to the same value. That value is an address of the string literal "aaa".

There are only 2 strings: One in array s1 and another is the string literal "aaa" existing someplace in memory.


When a pointer is compared to a pointer as in s2 == s3, those 2 addresses are compared, not the contents the point to. They are equal here as the compiled optimized as made on 1 "aaa" for both pointers to be initialized with.

When an array is compare to a pointer, as in s1 == s2, the array s1 is converted to the address of its first element &s1[0] and that address is compare to the pointer s2. The compare is false as the array and the string literal exist indifferent memory locations.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256