What is the difference between NULL, '\0' and 0?
Asked Answered
C

11

386

In C, there appear to be differences between various values of zero -- NULL, NUL and 0.

I know that the ASCII character '0' evaluates to 48 or 0x30.

The NULL pointer is usually defined as:

#define NULL 0

Or

#define NULL (void *)0

In addition, there is the NUL character '\0' which seems to evaluate to 0 as well.

Are there times when these three values can not be equal?

Is this also true on 64 bit systems?

Cardinale answered 18/8, 2009 at 22:9 Comment(2)
See #177489 for some more info into the differences between 0 and NULL.Valer
The identifier NUL does not exist in the C standard language or library (or in C++ as far as I know). The null character is sometimes called NUL, but it C or C++ it's usually just referred to as '\0'.Stutz
E
433

Note: This answer applies to the C language, not C++.


Null Pointers

The integer constant literal 0 has different meanings depending upon the context in which it's used. In all cases, it is still an integer constant with the value 0, it is just described in different ways.

If a pointer is being compared to the constant literal 0, then this is a check to see if the pointer is a null pointer. This 0 is then referred to as a null pointer constant. The C standard defines that 0 cast to the type void * is both a null pointer and a null pointer constant.

Additionally, to help readability, the macro NULL is provided in the header file stddef.h. Depending upon your compiler it might be possible to #undef NULL and redefine it to something wacky.

Therefore, here are some valid ways to check for a null pointer:

if (pointer == NULL)

NULL is defined to compare equal to a null pointer. It is implementation defined what the actual definition of NULL is, as long as it is a valid null pointer constant.

if (pointer == 0)

0 is another representation of the null pointer constant.

if (!pointer)

This if statement implicitly checks "is not 0", so we reverse that to mean "is 0".

The following are INVALID ways to check for a null pointer:

int mynull = 0;
<some code>
if (pointer == mynull)

To the compiler this is not a check for a null pointer, but an equality check on two variables. This might work if mynull never changes in the code and the compiler optimizations constant fold the 0 into the if statement, but this is not guaranteed and the compiler has to produce at least one diagnostic message (warning or error) according to the C Standard.

Note that the value of a null pointer in the C language does not matter on the underlying architecture. If the underlying architecture has a null pointer value defined as address 0xDEADBEEF, then it is up to the compiler to sort this mess out.

As such, even on this funny architecture, the following ways are still valid ways to check for a null pointer:

if (!pointer)
if (pointer == NULL)
if (pointer == 0)

The following are INVALID ways to check for a null pointer:

#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)

as these are seen by a compiler as normal comparisons.

Null Characters

'\0' is defined to be a null character - that is a character with all bits set to zero. '\0' is (like all character literals) an integer constant, in this case with the value zero. So '\0' is completely equivalent to an unadorned 0 integer constant - the only difference is in the intent that it conveys to a human reader ("I'm using this as a null character.").

'\0' has nothing to do with pointers. However, you may see something similar to this code:

if (!*char_pointer)

checks if the char pointer is pointing at a null character.

if (*char_pointer)

checks if the char pointer is pointing at a non-null character.

Don't get these confused with null pointers. Just because the bit representation is the same, and this allows for some convenient cross over cases, they are not really the same thing.

References

See Question 5.3 of the comp.lang.c FAQ for more. See this pdf for the C standard. Check out sections 6.3.2.3 Pointers, paragraph 3.

Exieexigency answered 18/8, 2009 at 22:10 Comment(23)
Thanks for pointing to the FAQ list. However, see also c-faq.com/null/nullor0.htmlMolloy
Good point, Sinan. It never occurred to me to do something as silly as use NULL as an integral value of zero.Exieexigency
No, the code you show is not valid. if(ptr == zero) ... will fail to translate. If you change it to if(ptr == '\0') ... then all three if statements are equivalent and always check for a null pointer.Flori
@litb First of all, this code is going to give several warnings (or errors possibly) about implicit conversions. Second, even if you replaced zero with '\0', you will be comparing ptr to all-bits-zero. In the first case, after conversions, you end up with 0xDEADBEEF == 0x00000000, which is false.Exieexigency
No, you won't compare ptr to all-bits-zero. This is not a memcmp, but this is a comparison using a builtin operator. The one side is a null pointer constant '\0', and the other side is a pointer. Aswell as with the other two versions with NULL and 0. Those three do the same things.Flori
You are taking the builtin comparison operator as a thing that would compare bit-strings. But that's not what it is. It compares two values, which are abstract concepts. So a null pointer that internally is represented as 0xDEADBEEF is still a null pointer, no matter what its bitstring looks like, and it will still compare equal to NULL, 0, \0 and all other null pointer constant forms.Flori
You make a good point about the comparison operator. I brushed up on C99. It says "An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant." It also says that a character literal is an integer constant expression. Thus, by the transitive property you're right that ptr == '\0'.Exieexigency
This answer is wrong. The C standard sets a null pointer value to 0. Even if the base machine uses 0xDEADBEEF as a null pointer, the standard doesn't change. It's up to the compiler to sort this out (and good luck to it). if (!pointer) will ALWAYS means if pointer is not 0 and is ALWAYS a valid way to check for a null pointer in C, as defined by the standard. According to A. Keeton's advice, if (!pointer) would fail on a machine where 0xDEADBEEF is the null pointerInessive
In fact there is another issue: unrelated types are not compared together. That means that when you try to compare a pointer to a char, both of them end up being converted into integers. The conversion in both cases end with the same integer value: 0.Valer
@Inessive !ptr will always be true in this example, no matter the representation of the null pointer. !ptr becomes ptr == 0 which is interpreted as is ptr the null pointer?Exieexigency
Just to emphasize: the answer is wrong and misleading. The three are equivalent with modern trends moving towards the plain 0 from the NULL macro.Valer
A null pointer value may well be different from address 0x0. It may well be 0xDEADBEEF. But it still compares equal to a null pointer constant. This is the same as true and false and their representation when stored. Now, just because stored false compare equal to 0, that doesn't mean that in binary, a boolean storing false is represented by all-bits-zero. Neither does it mean that if the boolean represents it as all-bits-one, it compares unequal to false. The semantics remain unchanged.Flori
@All Alright, I'm making my answer community wiki. Have fun :) (I was at my rep limit anyhoo)Exieexigency
@Andrew Keeton You're right! I meant "if (!pointer) will ALWAYS means if pointer is 0"Inessive
Back to basics: In Algebra 101 course, equality is transitive: given (a == b) and (b == c) then necessarily (a == c). In CompSci 101 that still holds true. Given 'mynull' integer variable equal to literal 0 and NULL equal to 0 (pointer and integer literal) then necessarily 'mynull' must be equal to NULL.Valer
that's only true if mynull never changes, which hopefully it wouldn't. Btu hopefully no one ever does it that way :) Read this parargraph: "To the compiler this is not a check for a null pointer, but an equality check on two variables. This might work if mynull never changes in the code and the compiler optimizations constant fold the 0 into the if statement, but this is not guaranteed and the compiler has to produce at least one diagnostic message (warning or error) according to the C Standard." ie I would't bank on it being the null constant.Inessive
wow, I made a lot of typos yesterday. I'd liek to blame the fact that it was 1.30am when I wrote that.Inessive
In C++, character literals are implemented as char not int.Scopoline
This answer currently only is about C. If you like to write a C++ part or sum up the differences to C++, then go and stuff it in. It's CW :)Flori
by 'references'... you mean 'further reading', right? :) And not C++ reference datatype, right?Tolyl
Since you're mentioning null pointers, what is a null pointer? That is not clear from your answer, but should probably be explained since it is central to the first half of the answer.Nonah
"....it might be possible to #undef NULL and redefine it to something wacky. Anyone doing this deserves to be shot." this my good sir made me laugh out loud...Rubidium
So would it be fair to say that when any variable is dropped into an if-statement, unless another condition is presented, the variable is compared with a default 0 value?Jumpy
V
43

It appears that a number of people misunderstand what the differences between NULL, '\0' and 0 are. So, to explain, and in attempt to avoid repeating things said earlier:

A constant expression of type int with the value 0, or an expression of this type, cast to type void * is a null pointer constant, which if converted to a pointer becomes a null pointer. It is guaranteed by the standard to compare unequal to any pointer to any object or function.

NULL is a macro, defined in as a null pointer constant.

\0 is a construction used to represent the null character, used to terminate a string.

A null character is a byte which has all its bits set to 0.

Vevine answered 18/8, 2009 at 22:48 Comment(1)
You missed 0.Keratoplasty
A
18

All three define the meaning of zero in different context.

  • pointer context - NULL is used and means the value of the pointer is 0, independent of whether it is 32bit or 64bit (one case 4 bytes the other 8 bytes of zeroes).
  • string context - the character representing the digit zero has a hex value of 0x30, whereas the NUL character has hex value of 0x00 (used for terminating strings).

These three are always different when you look at the memory:

NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20

I hope this clarifies it.

Antineutron answered 18/8, 2009 at 22:32 Comment(5)
Nasko: Evaluate sizeof('\0') and be surprised.Ivories
@Nasko: I was really surprised: with gcc, in C: sizeof('\0') == sizeof('a') == 4, while with g++, in C++: sizeof('\0') == sizeof('a') == 1Valer
@Nasko: From the C standard (draft,n1124): 'An integer character constant has type int', thus '\0' is actually of type int in C, and thus sizeof('\0') is 4 in my architecture (linux,32bit)Valer
@dribeas - I wasn't describing it as a constant, rather what you would see as part of the string. I definitely could have made it explicit. ThanksAntineutron
@DavidRodríguez-dribeas Undid edit "Corrected '0' ASCII value to 0x20 (dec 32)"Prestige
G
13

If NULL and 0 are equivalent as null pointer constants, which should I use? in the C FAQ list addresses this issue as well:

C programmers must understand that NULL and 0 are interchangeable in pointer contexts, and that an uncast 0 is perfectly acceptable. Any usage of NULL (as opposed to 0) should be considered a gentle reminder that a pointer is involved; programmers should not depend on it (either for their own understanding or the compiler's) for distinguishing pointer 0's from integer 0's.

It is only in pointer contexts that NULL and 0 are equivalent. NULL should not be used when another kind of 0 is required, even though it might work, because doing so sends the wrong stylistic message. (Furthermore, ANSI allows the definition of NULL to be ((void *)0), which will not work at all in non-pointer contexts.) In particular, do not use NULL when the ASCII null character (NUL) is desired. Provide your own definition

#define NUL '\0'

if you must.

Gregoor answered 18/8, 2009 at 22:38 Comment(0)
S
7

What is the difference between NULL, ‘\0’ and 0

"null character (NUL)" is easiest to rule out. '\0' is a character literal. In C, it is implemented as int, so, it's the same as 0, which is of INT_TYPE_SIZE. In C++, character literal is implemented as char, which is 1 byte. This is normally different from NULL or 0.

Next, NULL is a pointer value that specifies that a variable does not point to any address space. Set aside the fact that it is usually implemented as zeros, it must be able to express the full address space of the architecture. Thus, on a 32-bit architecture NULL (likely) is 4-byte and on 64-bit architecture 8-byte. This is up to the implementation of C.

Finally, the literal 0 is of type int, which is of size INT_TYPE_SIZE. The default value of INT_TYPE_SIZE could be different depending on architecture.

Apple wrote:

The 64-bit data model used by Mac OS X is known as "LP64". This is the common data model used by other 64-bit UNIX systems from Sun and SGI as well as 64-bit Linux. The LP64 data model defines the primitive types as follows:

  • ints are 32-bit
  • longs are 64-bit
  • long-longs are also 64-bit
  • pointers are 64-bit

Wikipedia 64-bit:

Microsoft's VC++ compiler uses the LLP64 model.

64-bit data models
Data model short int long  long long pointers Sample operating systems
LLP64      16    32  32    64        64       Microsoft Win64 (X64/IA64)
LP64       16    32  64    64        64       Most Unix and Unix-like systems (Solaris, Linux, etc.)
ILP64      16    64  64    64        64       HAL
SILP64     64    64  64    64        64       ?

Edit: Added more on the character literal.

#include <stdio.h>

int main(void) {
    printf("%d", sizeof('\0'));
    return 0;
}

The above code returns 4 on gcc and 1 on g++.

Scopoline answered 18/8, 2009 at 23:29 Comment(4)
No, '\0' is not a 1-byte value. It's a character literal, which is an integer constant expression - so if it can be said to have a size then it's the the size of an int (which has to be at least 2 bytes). If you don't believe me, evaluate sizeof('\0') and see for yourself. '\0', 0 and 0x0 are all completely equivalent.Ivories
@Ivories it depends on the language. If you don't believe me, try sizeof('\0') on a C++ compiler.Scopoline
you should use "%zu" when printing sizeof(something)Iffy
In C it is 4 on your computer just because of auto-cast which is int as default. assign that value without recast to a char, an int or a long long int and its size will change accordingly. Also size of 'a' is 4 out from a varable.Exhibitor
D
5

One good piece which helps me when starting with C (taken from the Expert C Programming by Linden)

The One 'l' nul and the Two 'l' null

Memorize this little rhyme to recall the correct terminology for pointers and ASCII zero:

The one "l" NUL ends an ASCII string,

The two "l" NULL points to no thing.

Apologies to Ogden Nash, but the three "l" nulll means check your spelling. 
  • The ASCII character with the bit pattern of zero is termed a "NUL".
  • The special pointer value that means the pointer points nowhere is "NULL".
  • The two terms are not interchangeable in meaning.
Deitz answered 4/11, 2013 at 6:16 Comment(1)
Much simpler: NUL is a control code such as BEL, VT, HT, SOT etc. and thus has max. 3 characters.Harlin
P
4

A one-L NUL, it ends a string.

A two-L NULL points to no thing.

And I will bet a golden bull

That there is no three-L NULLL.

How do you deal with NUL?

Polymyxin answered 19/8, 2009 at 0:22 Comment(0)
F
3

"NUL" is not 0, but refers to the ASCII NUL character. At least, that's how I've seen it used. The null pointer is often defined as 0, but this depends on the environment you are running in, and the specification of whatever operating system or language you are using.

In ANSI C, the null pointer is specified as the integer value 0. So any world where that's not true is not ANSI C compliant.

Fourposter answered 18/8, 2009 at 22:16 Comment(0)
M
3

A byte with a value of 0x00 is, on the ASCII table, the special character called NUL or NULL. In C, since you shouldn't embed control characters in your source code, this is represented in C strings with an escaped 0, i.e., \0.

But a true NULL is not a value. It is the absence of a value. For a pointer, it means the pointer has nothing to point to. In a database, it means there is no value in a field (which is not the same thing as saying the field is blank, 0, or filled with spaces).

The actual value a given system or database file format uses to represent a NULL isn't necessarily 0x00.

Maximomaximum answered 18/8, 2009 at 22:19 Comment(0)
O
1

NULL is not guaranteed to be 0 -- its exact value is architecture-dependent. Most major architectures define it to (void*)0.

'\0' will always equal 0, because that is how byte 0 is encoded in a character literal.

I don't remember whether C compilers are required to use ASCII -- if not, '0' might not always equal 48. Regardless, it's unlikely you'll ever encounter a system which uses an alternative character set like EBCDIC unless you're working on very obscure systems.

The sizes of the various types will differ on 64-bit systems, but the integer values will be the same.


Some commenters have expressed doubt that NULL be equal to 0, but not be zero. Here is an example program, along with expected output on such a system:

#include <stdio.h>

int main () {
    size_t ii;
    int *ptr = NULL;
    unsigned long *null_value = (unsigned long *)&ptr;
    if (NULL == 0) {
        printf ("NULL == 0\n"); }
    printf ("NULL = 0x");
    for (ii = 0; ii < sizeof (ptr); ii++) {
        printf ("%02X", null_value[ii]); }
    printf ("\n");
    return 0;
}

That program could print:

NULL == 0
NULL = 0x00000001
Overplus answered 18/8, 2009 at 22:15 Comment(21)
OP was asking about '\0' (the NUL character), not '0' (the zero character)Whalebone
Those will be the "obscure systems" that manage your bank accounts.Counterfoil
@Chris: '\0' is not NULL, it is byte 0 encoded in octal in a character literal.Overplus
In C++, the standard guarantees that the conversion from the integer value 0 to a pointer will always yield a null pointer. In C++, 0 is guaranteed to be null pointer, while on the other hand NULL is a macro and a malicious coder could redefine it as something different.Valer
And NULL is guaranteed to be 0. The bit pattern of a NULL pointer is not guaranteed to be all zeros, but the NULL constant is, and will always be, 0.Jennefer
@dribeas, @jalf: 0 is not guaranteed to be the NULL pointer, it's guaranteed to compare equal with the NULL pointer. An integer which is all-0 is 0, so if NULL is any bit pattern other than all-0, it cannot be 0.Overplus
@John: As far as I know, NULL is required to be defined as the constant expression 0. The actual contents of a null pointer is not required to be all zero bits. But NULL, the constant used to compare or assign null pointers, is just another name for the integer constant 0.Jennefer
Your first sentence is wrong - NULL cannot be defined as (void*)0 in C++ because there is no implicit conversion from a void * to another pointer (unlike in C).Counterfoil
In other words, assigning 0 or NULL to a pointer creates a null pointer, which has an implementation-defined representation. But 0 and NULL are defined to be identical.Jennefer
@Neil: the question seems to be regarding C. @jalf: No, 0 and NULL are equal, but NULL is not required to be 0. Assign NULL to a pointer and then inspect it in a debugger to see what its value is. On some architectures, it will be non-zero.Overplus
I really can't believe we are having this discussion. The properties of the null pointer are fairly well described in the various language standards.Counterfoil
@Neil: Agreed, and yet some people voted this answer down anyway. Apparently because they can't grasp the difference between equality and value.Overplus
@Neil: in which way is it wrong? In C, NULL is not guaranteed to be 0x00000000; It could be any bit pattern. The only guarantee is that it compares equal to 0 in pointer comparisons. Furthermore, the symbol NULL is typically defined to (void*)0.Overplus
As an aside, if I am incorrect, then the currently top-voted answer is also incorrect.Overplus
Please read my previous comments. This is my final contribution to this thread.Counterfoil
@John, if you say "it's not guaranteed to be 0x000000, it may well be (void*)0x00000" then you are right if you talk about C. But if you say "it's not guaranteed to be 0x0000, it may well be 0xDEADBEEF" then you are just bloody wrong, as others already told you. What you "proved" in your code was just that NULL converted to a pointer type can result in an address 0xDEADBEEF. That's why i refuse to talk about NULL pointers. That's just totally confusing terminology. Just say null pointer.Flori
@litb: NULL is a constant value. Obviously, it has to have some value, and that value might not be 0. I'm confused about why you differentiate between a "pointer with NULL assigned to it" and a "null pointer" -- isn't a null pointer a pointer variable which contains the value NULL?Overplus
i don't differentiate. But NULL is not a pointer with NULL assigned to it. "isn't a null pointer a pointer variable which contains the value NULL" No, not at all. A null pointer contains a pointer value (address), not an integer value. NULL is not an address. Even though some answers claim that NULL is a pointer value: It's NOT. The only special hack is `(void*)0´ in C, which is a valid NULL. But just ignore that, it's not important.Flori
see my cw edit to the top answer. NULL is defined to be a macro of the form "(void *) 0".Inessive
It might be (void*)0, but it might be aswell just 0. It's implementation defined what null pointer constant is used.Flori
your program is buggy: you declare a pointer, which we assume has a size of 8 bytes, then you assign the address of this pointer to an unsigned long pointer that you use in a for loop by indexing it but since you have declared the pointer unsigned long you you will move in memory for 8 times of sizeof (unsigned long) bytes and with the printf print for each group of sizeof (unsigned long) bytes the value of the least significant byte. To do what you wanted you would have to declare that pointer uint8_t * (or unsigned char *) and not unsigned long * (also print it in reverse order).Exhibitor
W
-2

(void*) 0 is NULL, and '\0' represents the end of a string.

Weizmann answered 20/9, 2017 at 8:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.