Question

NULL, '\0', and 0 in C: Differences and Proper Usage

cpointersnull

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.

  • 0 is 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 type int.
  • NULL is a macro for a null pointer constant. Its definition is implementation-provided, but it is commonly 0 or ((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:

  • 0 is the math department: it means no quantity.
  • '\0' is the text department: it is the special end marker in a C string.
  • NULL is 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.

Take Quiz

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:

  1. message contains three characters: 'O', 'K', and the automatically added terminator '\0'.
  2. message[0] == 'O' is true, so the first printf prints 1.
  3. message[2] == '\0' is true, because index 2 is the string terminator. The second printf prints 1.
  4. location is initialized with NULL, so it is a null pointer.
  5. location == NULL is true, so the last printf prints 1.

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: malloc returns 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 NULL when 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"), and strcpy rely on a final '\0' to know where text ends.

    char status[3] = {'O', 'K', '\0'};
    
  • Numeric counters and results: Use 0 for 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.

Take Quiz

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

ExpressionUsual purposeType before contextual conversionKey point
0Numeric zerointCan be a null pointer constant when used where a pointer is expected.
'\0'End of a C stringint in CHas value zero; use it when working with characters or string termination.
NULLMissing/invalid pointerDepends on its macro definitionUse it to clearly communicate null-pointer intent.
'0'The digit zero characterint in CDifferent 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.

Take Quiz

Cheat Sheet

  • 0 means integer zero.
  • '\0' means the character value zero; use it to terminate C strings.
  • '0' means the digit character zero, not numeric zero.
  • NULL means a null pointer by convention and macro definition.
  • NULL is commonly defined as 0 or ((void *)0).
  • 0 used 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 == NULL to test for a null pointer.
  • Use text[i] == '\0' to test for the end of a C string.
  • Use 0 for arithmetic and counts.
  • For printf("%p", ...), pass a void *, 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.

Take Quiz

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.

Take Quiz

Keep learning

Related questions

View more