Question
In C, what is the difference between NULL, the NUL character '\0', and the integer literal 0?
The character literal '0' represents the digit zero and commonly has the ASCII value 48 (0x30). A null pointer macro is often defined as either:
#define NULL 0
or:
#define NULL ((void *)0)
The NUL character '\0' also appears to have the value zero. Can NULL, '\0', and 0 ever differ in meaning, type, representation, or behavior? Does the answer change on 64-bit systems?
Short Answer
0, '\0', and NULL are closely related in C, but they communicate different intentions. 0 is an integer value, '\0' is the character value used to terminate C strings, and NULL is a macro intended for null pointers. C converts a null pointer constant such as 0 to the correct null pointer value when assigning or comparing pointers. This rule works on both 32-bit and 64-bit systems.
Concept
In C, zero can be used in several contexts. The context determines what it means.
0is an integer constant with the value zero.'\0'is a character constant whose value is zero. In C, ordinary character constants such as'A'and'\0'have typeint.NULLis a macro for a null pointer constant. Its definition is implementation-provided, but it is commonly0or((void *)0).
A null pointer is a pointer value guaranteed not to point to any object or function. It is not necessarily represented in memory as all zero bits. The compiler performs the required conversion when a null pointer constant is used in a pointer context.
int *number = 0; /* 0 converts to a null pointer */
int *other = NULL; /* NULL represents a null pointer */
'\0' has a different primary purpose: it marks the end of a C string.
char word[] = "cat";
/* Stored as: 'c', 'a', 't', '\0' */
The digit character '0' is completely different from '\0':
'0' /* the digit zero character, often 48 in ASCII */
'\0' /* numeric character value zero, used as a string terminator */
Although 0 and '\0' both have integer value zero, choose the form that expresses your intent: use NULL for pointers, '\0' for characters and strings, and 0 for numeric calculations.
Mental Model
Think of 0, '\0', and NULL as three labels that may refer to a similar “empty” idea in different departments:
0is the math department: it means no quantity.'\0'is the text department: it is the special end marker in a C string.NULLis the address department: it means “this pointer has no valid destination.”
The compiler can translate numeric zero into a null pointer when a pointer is expected. However, that does not mean a null pointer must physically be stored as zero bits, nor does it mean you should use the same spelling in every situation.
Syntax and Examples
Use the spelling that matches the kind of value you are working with.
#include <stddef.h>
int main(void) {
int count = 0; /* Numeric zero */
char terminator = '\0'; /* Character value zero */
int *pointer = NULL; /* Null pointer */
char name[] = "Ada";
if (count == 0) {
/* Numeric comparison */
}
if (name[3] == '\0') {
/* name ends after "Ada" */
}
if (pointer == NULL) {
/* Pointer does not point to an int */
}
(void)terminator;
return 0;
}
NULL may expand differently between implementations:
#define NULL 0
or:
#define NULL ((void *)0)
Both forms are valid null pointer constants in C. When assigned to an int *, char *, or function pointer, the language converts the null pointer constant to the appropriate null pointer value.
int *data = 0;
char *text = NULL;
void (*handler)(void) = 0;
For readability, prefer NULL when you mean a null pointer, even when 0 would work.
Step by Step Execution
Consider this example:
#include <stdio.h>
#include <stddef.h>
int main(void) {
char message[] = "OK";
char *location = NULL;
printf("%d\n", message[0] == 'O');
printf("%d\n", message[2] == '\0');
printf("%d\n", location == NULL);
return 0;
}
Step by step:
messagecontains three characters:'O','K', and the automatically added terminator'\0'.message[0] == 'O'is true, so the firstprintfprints1.message[2] == '\0'is true, because index2is the string terminator. The secondprintfprints1.locationis initialized withNULL, so it is a null pointer.location == NULLis true, so the lastprintfprints1.
The character terminator and null pointer are used in separate operations: one checks text storage, while the other checks an address-like value.
Real World Use Cases
-
Checking whether allocation failed:
mallocreturns a null pointer when it cannot allocate memory.int *items = malloc(10 * sizeof *items); if (items == NULL) { /* Handle allocation failure */ } -
Representing an optional pointer: A search function may return
NULLwhen no matching object exists.struct User *user = find_user("sam"); if (user == NULL) { /* No user was found */ } -
Ending strings: Functions such as
strlen,printf("%s"), andstrcpyrely on a final'\0'to know where text ends.char status[3] = {'O', 'K', '\0'}; -
Numeric counters and results: Use
0for quantities, indexes, flags, and arithmetic.size_t processed = 0; -
Binary data: A zero byte is not automatically an end marker unless an API treats the data as a C string. A file buffer can legally contain
'\0'in the middle.
Real Codebase Usage
In real C projects, the spelling often documents the value's role.
Pointer guard clauses
Check pointer inputs before dereferencing them.
#include <stddef.h>
void print_first(const char *text) {
if (text == NULL) {
return;
}
/* Safe to read text[0] after this check. */
}
Allocation error handling
#include <stdlib.h>
int *make_numbers(size_t count) {
int *numbers = malloc(count * sizeof *numbers);
if (numbers == NULL) {
return NULL;
}
return numbers;
}
Explicit string termination
When building text manually, reserve room for and write '\0'.
char code[4];
code[0] = 'C';
code[1] = 'A';
code[2] = 'T';
code[3] = '\0';
Length-aware binary APIs
Do not use string functions when bytes may contain zero values. Pass a pointer and an explicit length instead.
void send_bytes(const unsigned char *data, size_t length);
Here, data may be NULL only if the API documents that it is allowed for the given length; zero-valued bytes within the data are ordinary data.
Common Mistakes
Confusing '0' with '\0'
char wrong = '0'; /* Digit character, not string terminator */
char right = '\0'; /* Zero-valued character */
'0' is the printable digit. In ASCII, it has value 48; '\0' has value 0.
Using NULL as a character terminator
This may compile on systems where NULL is defined as 0, but it expresses the wrong idea and can fail if NULL is a pointer expression.
char text[2] = {'A', NULL}; /* Avoid this */
char fixed[2] = {'A', '\0'};
Use '\0' for a character or byte that ends a C string.
Dereferencing a null pointer
int *value = NULL;
*value = 10; /* Undefined behavior */
Check that a pointer is non-null before dereferencing it, unless your function contract guarantees it is valid.
Assuming a null pointer is all-bits-zero
Do not create a null pointer by manually manipulating pointer bytes. Use NULL or 0 in a pointer context.
int *pointer = NULL; /* Correct */
C guarantees the conversion from a null pointer constant, not a particular bit pattern for every pointer type.
Passing NULL to a variadic function as though it were always void *
If NULL is defined as 0, it has integer type before conversion. In a variadic call, arguments do not have a destination parameter type that causes pointer conversion.
#include <stdio.h>
printf("%p\n", NULL); /* Do not rely on this being correct everywhere */
printf("%p\n", (void *)NULL); /* Correct for %p */
The %p conversion expects a void * argument. Cast explicitly when needed.
Comparisons
| Expression | Usual purpose | Type before contextual conversion | Key point |
|---|---|---|---|
0 | Numeric zero | int | Can be a null pointer constant when used where a pointer is expected. |
'\0' | End of a C string | int in C | Has value zero; use it when working with characters or string termination. |
NULL | Missing/invalid pointer | Depends on its macro definition | Use it to clearly communicate null-pointer intent. |
'0' | The digit zero character | int in C | Different from '\0'; commonly value 48 in ASCII. |
NULL versus 0 for pointers
int *a = NULL;
int *b = 0;
Both create null pointers. NULL is usually clearer in pointer-oriented code.
'\0' versus 0 in a character array
char a = '\0'; /* Clearly a character/string terminator */
char b = 0; /* Same stored value after conversion, less descriptive */
Both can store a zero-valued char, but '\0' better explains why the value is present.
32-bit versus 64-bit systems
The rules do not change with pointer width. A null pointer can still be made from NULL or 0 in pointer contexts. A 64-bit pointer may be larger than an int, which is another reason not to treat integer 0 as though it were already a pointer value in contexts such as variadic function calls.
Cheat Sheet
0means integer zero.'\0'means the character value zero; use it to terminate C strings.'0'means the digit character zero, not numeric zero.NULLmeans a null pointer by convention and macro definition.NULLis commonly defined as0or((void *)0).0used where a pointer is expected converts to that pointer type's null pointer value.- A null pointer is not required to have an all-zero-bit representation.
- Use
pointer == NULLto test for a null pointer. - Use
text[i] == '\0'to test for the end of a C string. - Use
0for arithmetic and counts. - For
printf("%p", ...), pass avoid *, for example(void *)pointer. - The language rules are the same on 32-bit and 64-bit systems.
FAQ
Is NULL always equal to zero in C?
NULL is a macro for a null pointer constant, commonly 0 or ((void *)0). It represents a null pointer when used in a pointer context, but its macro expansion does not have to have the same type as integer 0.
Is '\0' the same as NULL?
They can both involve zero, but they have different intended uses. Use '\0' to terminate strings and NULL to represent a null pointer.
Is '\0' equal to 0 in C?
Yes. The character constant '\0' has value zero and type int in C. Still, it is clearer to use '\0' when you mean a character terminator.
Why is '0' different from '\0'?
'0' is the character used to display the digit zero. '\0' is the character value zero. In ASCII, '0' is 48, while '\0' is 0.
Does a null pointer contain all zero bits?
Not necessarily. C guarantees that using a null pointer constant such as 0 or NULL produces a null pointer in a pointer context. It does not require every pointer type's null representation to be all zero bits.
Should I use NULL or 0 for a null pointer?
Use NULL in ordinary pointer code because it communicates intent. Use 0 for numbers. Both are valid for initializing or comparing pointers in C.
Does this behave differently on 64-bit systems?
No. The null-pointer conversion rules are the same. However, pointers can be wider than int, so avoid assumptions that an integer argument is interchangeable with a pointer argument in variadic calls.
Can a C string contain '\0' in the middle?
A character array can contain it, but standard C string functions stop at the first '\0'. Use an explicit length when processing binary data or embedded zero bytes.
Mini Project
Description
Create a small utility that safely inspects a C string. It demonstrates the separate roles of NULL, '\0', and numeric 0: a null pointer means no string was supplied, while the NUL character marks the end of a valid string.
Goal
Write a function that counts the characters in a string without using strlen and safely handles a NULL input.
Requirements
Include <stddef.h> for NULL.
Keep learning
Related questions
2D Array Loop Order and Cache Performance in C
Learn why swapping nested loops changes 2D array performance in C, using row-major memory layout, cache locality, and practical benchmarks.
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.