55

Inspired by a program described in K&R section 5.5:

void strcpy(char *s, char *t)
{
    while(*s++ = *t++);
}

C program

if ('\0') { printf("\'\\0\' -> true \n"); }
else      { printf("\'\\0\' -> false\n"); }

if ("\0") { printf("\"\\0\" -> true \n"); }
else      { printf("\"\\0\" -> false\n"); }

prints

'\0' -> false
"\0" -> true

Why do '\0' and "\0" evaluate differently in C?

clang version 3.8.0

Community
  • 1
  • 1
Rahn
  • 4,787
  • 4
  • 31
  • 57

9 Answers9

121

Recall how string literals work in C - "\0" is a character array containing two zero bytes (the one you asked for, and the implicit one at the end). When evaluated for the if test, it decays into a pointer to its first character. This pointer is not NULL, so it's considered true when used as a condition.

'\0' is the number zero, equivalent to just 0. It's an integer which is zero, so it's considered false when used as a condition.

Medinoc
  • 6,577
  • 20
  • 42
user253751
  • 57,427
  • 7
  • 48
  • 90
  • The proposed edit to this answer is wrong. The slash is an escape character and not a character in itself. I.e. `echo 'int main() { printf("%lu\n", sizeof("\0")); return 0; }' | gcc -x c -; ./a.out` gives `2`. `\0` is an integer that represents a NULL terminator. – tangrs Apr 30 '16 at 04:13
  • 4
    @M.M: it's a string literal ;) – knittl Apr 30 '16 at 08:24
  • 21
    Yes, string literals are arrays of char – M.M Apr 30 '16 at 08:39
  • 8
    This "*`"\0"` is a pointer to a character array*" does not suite well a 28++ voted answer, as it's simply wrong in two ways. `"\0"` s not a pointer, but an array, and if this array would be decayed to a pointer due to whatever reasons it wouldn't point to the array but to its 1st element. – alk Apr 30 '16 at 12:02
  • @alk But it's a _constant_ string we're talking about here. Also, any pointer to an array is always also a pointer to its first element. – Mr Lister Apr 30 '16 at 15:04
  • 4
    @MrLister Pointer to an array and pointer to an element of an array are two different beasts. – Spikatrix Apr 30 '16 at 15:12
  • 4
    @MrLister `char (*ptr)[] = &"test";` would be a pointer to the string literal while `char* ptr = "test";` would be a pointer to the address of the first character of the string literal `"test"`. – Spikatrix Apr 30 '16 at 15:20
  • 4
    @MrLister: "*any pointer to an array is always also a pointer to its first element.*" correct by value, wrong by type. – alk Apr 30 '16 at 15:56
  • 1
    @CoolGuy: Given `char (*p1)[] = &"lo"; char *p2 = &"Hello";` would there be any guarantee that `(*p1)` identifies to the first character of "an array" rather than e.g. the fourth character of the array identified by `p2`? – supercat Apr 30 '16 at 22:18
  • @supercat I assume you meant `char *p2 = "Hello";`? Anyway, I'm not sure about that. I guess it might, when you use `-fwritable-strings`. – Spikatrix May 01 '16 at 05:11
  • @supercat: No I don't believe so. – Lightness Races in Orbit May 01 '16 at 11:32
41

First of all, you need to keep in mind that in C,

  • Zero is false and non-zero is true.
  • For pointer types, NULL is false and non-NULL is true.

'\0', as others have said, is the same as the integer literal 0 and hence is false (See first bullet point above to know why).

"\0" is a string literal that contains two \0 characters (One which you have explicitly added and the other, which is implicit and will be added by the compiler). The string literal will be stored somewhere in read-only memory. When you use "\0", it gets converted to a pointer to its first element. This is commonly referred to as "array decay". (This is the reason why stuff like char* str = "string"; works).

So, you are effectively checking the address of the first character of the string literal. Since the address of the string literal will always be non-NULL, the if will always be true (See second bullet point above to know why).


: This "decay" of arrays does not always happen. See Exception to array not decaying into a pointer?

Community
  • 1
  • 1
Spikatrix
  • 20,225
  • 7
  • 37
  • 83
  • You're right of course about the value 0 being false. However, a char is not necessarily the same as an integer. An int is always signed unless you explicitly specify unsigned. Whether a char is signed or not is implementation dependent! – Mr Lister Apr 30 '16 at 15:08
  • 2
    `'\0'` is an `int`, IIRC, although it _looks_ like a `char`. – Spikatrix Apr 30 '16 at 15:12
  • 4
    Also, I'm not sure how `unsigned` and `signed` is relevant here. I mean `unsigned` or `signed`, `char` or `int`, all can represent 0. – Spikatrix Apr 30 '16 at 15:15
  • Which shows the problem with the (IMHO too common) shorthand test for 0/NULL. If the OP had written e.g. "if ("\0" == NULL), it'd be pretty obvious what the problem was. – jamesqf Apr 30 '16 at 18:11
  • 2
    Just a note, `'\0'` would be `char` in C++, although it's `int` in C. – Ruslan May 01 '16 at 11:24
16

'\0' is a number: 0, so it is evaluated as false (0 = false, !0 = true).

But "\0" is a pointer to a read-only section where the actual string is stored, the pointer is not NULL ergo it's true.

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
FedeWar
  • 537
  • 1
  • 7
  • 17
  • `"\0"` is not a pointer. It's a string literal, whose value is an array (which is implicitly converted to a pointer in most but not all contexts). – Keith Thompson May 06 '16 at 21:56
3

First, looking at the two conditions, '\0' is a constant of type integer, which denotes the null character C, which is the same as 0. While "\0" is a string literal, which contains 2 bytes, the one specified and the null terminator byte implicitly added. Being a string literal, the pointer cannot be NULL.

Second, in C, for the condition of if statement, everything non-zero is evaluated as true, and zero is evaluated as false.

According to this rule, it will be clear that '\0' is false, and "\0" evaluated as true.

fluter
  • 13,238
  • 8
  • 62
  • 100
  • 1
    Your answer does not explain why `"\0"` would be considered `true`. – alk Apr 30 '16 at 11:18
  • @alk `"\0"` would be `true`, not `false`. – fluter Apr 30 '16 at 11:19
  • I said it's a string literal, which cannot be `NULL`, that's why it is `true`. – fluter Apr 30 '16 at 11:19
  • 1
    I know this. But it's not obvious from your answer. Not obvious for someone who does ***not*** know that a "string" under certain conditions decays to a pointer to its 1st element, as probably the OP does not. – alk Apr 30 '16 at 11:22
  • "*Being a string literal, the pointer cannot be `NULL`.*" -- It would be helpful to explain what pointer you're referring to (though other answers already cover that). – Keith Thompson May 06 '16 at 21:57
3

First of all, please note that the hexadecimal value of False is 0x00 and True is any other value than 0x00.

"\0" is a string with a character and Null Terminator '\0' at the end. So it is a character pointer, pointing to an array of 2 bytes: ['\0', '\0']. In this array, the first one is the character and the other one is the null terminator.

After compiling (without optimizing), this character pointer is temporarily assigned to an address in the memory pointing to the first byte of these two bytes. This address might be, for example, 0x18A6 in hexadecimal. So the compiler (most of them) actually writes these two values to the memory. Because a string is actually the address of the first byte of that string, our expression is interpreted as 0x18A6 != false . So, it is clear 0x18A6 != 0x00 is True.

'\0' is simply 0x00 in hexadecimal. 0x00 != 0x00 is False.

This answer is written for 8-bit data architecture with 16-bit addressing. I hope that helps.

Bora
  • 1,402
  • 16
  • 19
0

'\0' is a null character which has the value of 0. It is used to terminate a string of characters. So it's consider false.

"\0" is a null or empty string. The only character in the string is the null character which terminates the string.So it's consider true.

msc
  • 33,420
  • 29
  • 119
  • 214
  • 4
    It is not just "considered true" like that. A string literal in C is just a pointer to its first element, and that is what is being evaluated to true. – Lemon Drop Apr 30 '16 at 05:13
  • 2
    @lemondrop a string literal is not a pointer. A string literal may be converted to a pointer in some contexts (such as OP's code) – M.M Apr 30 '16 at 07:54
  • 3
    "*The only character in the string is the null character which terminates the string*" this is not entirely true. This "string" (`"\0"`) holds ***two*** `'\0'` characters. – alk Apr 30 '16 at 11:12
  • 2
    "*So it's consider true.*" And where this "*So*" pulls any evidence from, why the literal `"\0"` would evaluate to "*true*" is not obvious from your answer. – alk Apr 30 '16 at 11:15
  • 2
    @cat `sizeof ""` is not equal to `sizeof "\0"`. – alk Apr 30 '16 at 11:27
  • 1
    @cat: No offence, all true, but you seem to be drifting away ... :-) All I was trying to pick on was this "*The only character in ...*", which simply is wrong. – alk Apr 30 '16 at 11:33
  • @cat if an array is given as operand to `==` then it is converted to a pointer. The array is different to the pointer, in the same way that `5` is different to `5.0` in the code `5 == 6.0`. You can verify this by comparing `sizeof "\0"` with the size of a pointer. – M.M Apr 30 '16 at 14:17
  • @cat: There are times when it's useful to have an API which will need multiple constant strings take a single pointer and then interpret the portion up to the first zero byte as the first, the portion from there to the next zero byte as the second, etc. The pattern is not terribly common, but the meaning of `"FOO\0" "BAR\0" "23 skidoo"` is defined [the closing and re-opening quotes before the last zero byte are more readable than would be `\00023 skidoo`, and it's IMHO cleaner to include such quotes consistently than only where needed. – supercat Apr 30 '16 at 22:12
0

'\0' is a char that is equal to number zero. "\0" is a string and we usually add '\0' at the end of a string. Don't use '\0' or "\0" in a conditional statements because it's quite confusing.

The following usage is suggested:

if (array[0] != 0)
{

}

if (p != 0)
{

}

if (p != NULL)
{

}
G.Mather
  • 9
  • 3
  • I would always prefer to see `'\0'` used in conditionals, because it indicates that you are handling the 'thing' as a string, not an array of numbers. – Attie Mar 21 '17 at 13:23
0

Check out this with examples..

#include <stdio.h> 

int main() 
{ 
printf( "string value\n" ); 

//the integer zero 
printf( "0.........%d\n" , 0 ); 

//the char zero, but chars are very small ints, so it is also an int 
//it just has some special syntax and conventions to allow it to seem 
//like a character, it's actual value is 48, this is based on the 
//ASCII standard, which you can look up on Wikipedia 
printf( "'0'.......%d\n" , '0' ); 

//because it is an integer, you can add it together, 
//'0'+'0' is the same as 48+48 , so it's value is 96 
printf( "'0'+'0'...%d\n" , '0'+'0' ); 

//the null terminator, this indicates that it is the end of the string 
//this is one of the conventions strings use, as a string is just an array 
//of characters (in C, at least), it uses this value to know where the array 
//ends, that way you don't have to lug around another variable to track 
//how long your string is. The actual integer value of '\0' is zero. 
printf( "'\\0'......%d\n" , '\0' ); 

//as stated, a string is just an array of characters, and arrays are tracked 
//by the memory location of their first index. This means that a string is 
//actually a pointer to the memory address that stores the first element of 
//the string. We should get some large number, a memory address 
printf( "\"0\".......%d\n" , "0" ); 

//a string is just an array of characters, so lets access the character 
//in position zero of the array. it should be the character zero, which 
//has an integer value of 48 
printf( "\"0\"[0]....%d\n" , "0"[0] ); 

//and the same thing for the empty string 
printf( "\"\\0\"[0]...%d\n" , "\0"[0] ); //equal to '\0' 

//we also said a string is just a pointer, so we should be able to access 
//the value it is pointing to (the first index of the array of characters) 
//by using pointers 
printf( "*\"0\"......%d\n" , *"0" ); 

return 0; 
}
Krishna
  • 51
  • 9
0

The simple thing is ATLEAST 0 (int) and 0.0 (float or double) have FALSE value in C.

'\0' is integer 0.

"\0" is an array of characters. It does not matter that INSIDE the array how many Characters are there or what are those characters.

So, '\0' evaluates to 0 like 77-77 evaluates to 0. And 0 is false.

int x; x = '\0'; printf("X has a value : %d"); Output:


x has a value : 0

And the code:

if(0){printf("true");}

else{printf("false");}

Output:


false