Menu

NULL Pointers in C: What NULL Means and How to Check for It

NULL is the address a pointer holds when it points at nothing. This page covers what NULL really is, why dereferencing it crashes, how it differs from 0 and from an uninitialized pointer, and the defensive patterns that keep null bugs out of your code.

This page includes runnable editors - edit, run, and see output instantly.

A pointer always holds some value. When it has no object to point at yet - before it is assigned, after the thing it pointed at is freed, or when a function has nothing to return - it needs a value that unmistakably means "nothing here". That value is the null pointer, and NULL is the name you write.

The discipline around it is small and pays for itself constantly: set pointers to NULL when they have no target, check for NULL before dereferencing, and return NULL when you have no result.

What NULL Actually Is

NULL is a macro, defined in <stddef.h> and also pulled in by <stdio.h>, <stdlib.h>, <string.h>, and others. It expands to a null pointer constant - typically ((void*)0) or plain 0.

The C standard guarantees the property that matters: a null pointer compares unequal to a pointer to any actual object or function. Two null pointers of the same type always compare equal to each other.

Most systems print (nil) or 0x0 for the null pointer - address zero. That is a common implementation, not a rule; the standard never promises the bits are zero. What it promises is the comparison, so write p == NULL, never anything that depends on the representation.

Dereferencing NULL Crashes

The reason for every null check in existence:

int *p = NULL;
printf("%d\n", *p);   // undefined behavior - almost certainly a crash

On Windows, macOS, and Linux the first page of the address space is deliberately left unmapped, so the CPU traps the access and the operating system kills the program. You will see:

Segmentation fault (core dumped)          # Linux
zsh: segmentation fault  ./program        # macOS

That immediate crash is a feature. It converts a logic bug into a loud failure at the exact line that caused it, instead of a silent corruption you find three weeks later. See segmentation fault for how to read the crash and find the line.

This is why "null pointer" is not an exception you catch in C. There is no mechanism to recover; there is only checking beforehand.

Check What Might Fail

Functions that can fail signal it by returning NULL. Checking is not optional politeness - the crash is the alternative.

The standard library is full of these: malloc, calloc, realloc, fopen, strchr, strstr, getenv, bsearch. Every one of them answers "no result" with NULL. See dynamic memory for the full allocation story.

Two idioms for the check, both common:

if (p == NULL) { /* handle */ }   // explicit - preferred for clarity
if (!p)        { /* handle */ }   // terse - relies on NULL being falsy

A null pointer tests as false in a condition and a valid pointer as true, so both work. The explicit form reads better when a stranger is scanning your code for bugs.

NULL vs 0 vs Uninitialized

Three distinct situations that beginners blur together:

int *a = NULL;     "points at nothing" - testable, safe to check
int *b;            uninitialized - holds garbage, NOT testable
int *c = &x;       points at a real object

The dangerous one is b. Its bytes are whatever was left in that stack slot, which might be zero (and look fine) or might be a plausible-looking address from an earlier call. No check can distinguish it from a valid pointer, and the behavior changes between debug and release builds.

Initialize every pointer. If you have no address yet, NULL is the address. Compile with -Wall -Wextra and the compiler will flag many uninitialized uses for you.

On 0: in a pointer context the integer constant 0 is the null pointer constant, so p = 0; is valid C. Prefer NULL anyway. It signals intent, and it matters in variadic calls where the compiler cannot convert for you:

execl("/bin/ls", "ls", 0);       // risky - may pass an int where a pointer is expected
execl("/bin/ls", "ls", (char *)NULL);   // correct

C23 adds nullptr, a keyword with its own type that avoids this class of ambiguity entirely; NULL remains correct and portable everywhere.

Defensive Patterns

Guard at the top of a function that takes pointers.

Set to NULL after freeing. free does not change your pointer - it only releases the memory. The stale pointer left behind is a dangling pointer, and using it is undefined behavior that often does not crash right away.

Two facts inside that example are worth committing to memory. free(NULL) is defined to do nothing, so cleanup code never needs to guard it. And setting p = NULL after free turns a use-after-free - which may silently corrupt data - into an immediate, debuggable crash.

Return NULL to mean "no result", and say so.

// returns a pointer to the matching element, or NULL if there is none
int *find(int *arr, int n, int target);

Document it in the comment above the function. A caller who knows a NULL is possible writes the check; one who does not, will not.

A Quick Checklist

  • Initialize every pointer, with a real address or with NULL.
  • Check the return of malloc, calloc, realloc, and fopen before using it.
  • Check pointer parameters at the top of any function that could be called with bad input.
  • Set pointers to NULL immediately after free.
  • Write NULL, not 0, whenever a pointer is meant.
  • Build with -Wall -Wextra and, when you can, run under a sanitizer: gcc -fsanitize=address,undefined catches null dereferences with a precise report.

Frequently Asked Questions

What is a NULL pointer in C?

A pointer holding the null pointer constant - a value guaranteed to compare unequal to the address of any real object. It is the standard way to say "this pointer points at nothing yet", and NULL is the macro for it, defined in <stddef.h> and several other headers.

What happens if you dereference a NULL pointer in C?

It is undefined behavior. In practice, on desktop and server systems, it crashes immediately with a segmentation fault because address zero is deliberately left unmapped. On embedded systems without memory protection it may silently read or corrupt something instead, which is far worse.

Is NULL the same as 0 in C?

In pointer contexts, yes: the integer constant 0 is the null pointer constant, so p = 0; and p == NULL both work. But use NULL for pointers and 0 for numbers - it tells the reader which of the two you meant, and it keeps variadic calls safe, where a bare 0 may be passed as an int rather than a pointer.

What is the difference between a NULL pointer and an uninitialized pointer?

A NULL pointer definitely points at nothing, and you can test for it. An uninitialized pointer holds whatever bytes happened to be in that memory - possibly a valid-looking address - so there is no test that can catch it. Always initialize pointers to NULL when you have nothing better.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED