CNULL & Dangling Pointers

NULL & Dangling Pointers

A pointer variable always holds some address, but that address is not always a safe one to use. Two of the most common ways a pointer goes wrong are being NULL (deliberately "points to nothing") and being dangling (pointing to memory that is no longer valid). Both are behind a huge share of real-world C crashes and security bugs, so learning to recognize and guard against them is essential.

NULL: "points to nothing"

NULL is a special pointer value, defined in <stddef.h> (and several other standard headers), that is guaranteed not to point at any valid object. It is the conventional way to say "this pointer currently has no target" — used to initialize pointers before they are assigned a real address, and to signal failure from functions like malloc, which returns NULL when it cannot allocate memory.

Dereferencing NULL crashes the program
Reading or writing through a NULL pointer is undefined behavior. On most systems it triggers a segmentation fault and the program is terminated immediately — there is no partial or "lucky" outcome to rely on.

C
#include <stdio.h>

int main(void) {
    int *p = NULL;

    printf("about to crash...\n");
    printf("%d\n", *p);   // undefined behavior: NULL pointer dereference

    return 0;
}
about to crash...
Segmentation fault (core dumped)

The fix is always the same: check a pointer against NULL before dereferencing it, especially after any function that can return NULL on failure, such as malloc, fopen, or strchr.

C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *p = malloc(sizeof(int));

    if (p == NULL) {
        fprintf(stderr, "allocation failed\n");
        return 1;
    }

    *p = 42;                 // safe: we know p is not NULL here
    printf("%d\n", *p);
    free(p);

    return 0;
}
Dangling pointers: valid-looking, but not valid

A dangling pointer is more dangerous than a NULL pointer precisely because it does not look obviously wrong — it holds an address that used to be valid, but the memory at that address has since been freed or gone out of scope. Using it is undefined behavior: it might appear to work, corrupt unrelated data, or crash, and the behavior can change from run to run.

The classic example is returning the address of a local (automatic) variable from a function. Once the function returns, its local variables no longer exist — the stack space they occupied is free to be reused by the next function call.

Never return the address of a local variable
This compiles (often with just a warning), but it is undefined behavior:

C
#include <stdio.h>

int *make_dangling(void) {
    int local = 99;
    return &local;      // BUG: local's storage ends when the function returns
}

int main(void) {
    int *p = make_dangling();
    printf("%d\n", *p); // undefined behavior: reading freed stack memory
    return 0;
}

The fix is to give the value storage that outlives the function — either allocate it dynamically with malloc (and have the caller free it), or have the caller pass in a pointer to memory it already owns.

C
#include <stdio.h>
#include <stdlib.h>

int *make_valid(void) {
    int *p = malloc(sizeof(int));
    if (p != NULL) {
        *p = 99;
    }
    return p;   // heap memory outlives the function call
}

int main(void) {
    int *p = make_valid();
    if (p != NULL) {
        printf("%d\n", *p);   // well-defined
        free(p);
        p = NULL;
    }
    return 0;
}
99
The other common cause: use-after-free

A pointer also dangles the moment you free the memory it points to — the pointer variable itself still holds the old address, but that address is no longer yours to use.

C
int *p = malloc(sizeof(int));
*p = 5;
free(p);

printf("%d\n", *p); // undefined behavior: use-after-free, p is dangling
Set it to NULL right after freeing
Immediately after `free(p)`, set `p = NULL;`. A NULL dereference crashes loudly and immediately at the exact spot of the bug; a dangling pointer can silently corrupt memory far away from where the real mistake was made. Making the pointer NULL turns a hard-to-find bug into an easy one, and it makes a later, accidental double `free(p)` harmless as well (`free(NULL)` is defined to do nothing).
  • Always initialize pointers, and check pointers returned from malloc/fopen/etc. against NULL before dereferencing.

  • Never return the address of a local (automatic) variable from a function.

  • A pointer becomes dangling the instant the memory it points to is freed or goes out of scope, even though its value looks unchanged.

  • Set a pointer to NULL immediately after freeing it to convert future misuse into a safe no-op or an obvious crash.