Skip to content

Intermediate · Pointers · topic 25 of 60 · 30 min

NULL, dangling pointers and pointers to pointers

Explanation

NULL is a pointer that points nowhere; dereferencing it crashes (a segmentation fault on most systems), so check pointers before use. Uninitialised (wild) pointers and dangling pointers (to memory that was freed or went out of scope) are worse, because they may seem to work. A pointer to a pointer (int **pp) lets a function change the caller's pointer. Read complex declarations from the name outward.

NULL

c
int *p = NULL;           /* "points to nothing" (in C23 you can also write nullptr) */
if (p != NULL) {          /* or simply: if (p) */
    printf("%d\n", *p);
}
/* *p without the check: undefined behaviour, usually "Segmentation fault" */

Functions use NULL to signal "nothing": strchr returns NULL when the character is not found, fopen returns NULL when a file cannot be opened, malloc returns NULL when memory runs out (module 6). Always check these returns.

Wild pointers

c
int *p;          /* uninitialised: holds a random address */
*p = 5;          /* writes to an unknown place: may crash, may silently corrupt memory */
Initialise every pointer: to a valid address, or to NULL.

Dangling pointers

A dangling pointer still holds an address, but the object there no longer exists: a local variable whose function returned, or heap memory that was freed (module 6). Using it is undefined behaviour and may appear to work in testing, then fail in production when the memory is reused.

c
int *p;
{
    int temp = 10;
    p = &temp;
}                     /* temp's lifetime ends here */
printf("%d\n", *p);   /* dangling: undefined behaviour */
Careful: Segmentation faults ("segfault") mean the program touched memory it was not allowed to, very often through a NULL, wild or dangling pointer. The crash line is not always where the bug is: the pointer may have gone bad much earlier. Compile with -g -fsanitize=address and use gdb's backtrace (module 11) to find the real cause.

Pointers to pointers

output
int x = 5;
int *p = &x;
int **pp = &p;

address   name   value
0x100     x      5
0x108     p      0x100   ──► x
0x110     pp     0x108   ──► p ──► x

*pp   → 0x100 (the value of p)
**pp  → 5     (the value of x)

The main use: a function that must change the CALLER's pointer (make it point somewhere else, or allocate memory for it) needs the address of that pointer, an int **.

c
void find_first_negative(int *a, int n, int **result) {
    *result = NULL;
    for (int i = 0; i < n; i++) {
        if (a[i] < 0) { *result = &a[i]; return; }   /* changes the caller's pointer */
    }
}
int *neg;
int data[] = {4, -2, 7};
find_first_negative(data, 3, &neg);                  /* neg now points to data[1] */

argv and arrays of strings

char *argv[] in main is an array of pointers to char (each pointing to one argument string); as a parameter it is the same as char **argv. argv[1][0] is the first character of the first user argument.

Reading declarations

DeclarationRead it as
int *pp is a pointer to int
int **pppp is a pointer to a pointer to int
int *a[3]a is an array of 3 pointers to int
int (*a)[3]a is a pointer to an array of 3 ints
char *argv[]argv is an array of pointers to char
int (*f)(int)f is a pointer to a function taking int and returning int (module 9)
Think of it like this: A dangling pointer is like a phone number saved for a friend who changed numbers: the number still dials, but someone else answers now. NULL is an empty contact entry: obviously empty, so you do not call it. A wild pointer is a number you never saved, just random digits.
Tip: After freeing memory or when an object goes away, set the pointers that referred to it to NULL. A NULL dereference crashes immediately and loudly, which is much easier to debug than silent corruption.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

NULL, dangling pointers and pointers to pointers · 1/6

Pointer pitfalls

In this lesson you will learn the dangerous pointer mistakes and how to avoid them.

Prefer a video by a teacher? Find free videos on “c null pointer dangling pointer wild pointer double pointer explained” on YouTube ↗

In real life: A lookup that may find nothing

A hospital system looks up a patient record by ID in an in-memory table. The function returns a pointer to the record or NULL if there is no such patient. Every caller checks for NULL before using the result, so a mistyped ID shows a message instead of crashing the reception terminal.

c
struct Patient { int id; char name[40]; };

struct Patient *find_patient(struct Patient *table, int n, int id) {
    for (int i = 0; i < n; i++) if (table[i].id == id) return &table[i];
    return NULL;
}

struct Patient *p = find_patient(table, count, 1042);
if (p == NULL) printf("No patient with ID 1042\n");
else printf("Patient: %s\n", p->name);

Practice (0/3 done)

Task 1 · Question

What does this print? int x = 1, y = 2; int *p = &x; int **pp = &p; *pp = &y; **pp = 9; printf("%d %d\n", x, y);

Task 2 · Question

Which line is undefined behaviour? 1: int *p = NULL; 2: int *q; 3: if (p) *p = 1; 4: *q = 1;

Task 3 · Practice

Write int find_max_ptr(int *a, int n, int **out) that sets *out to point at the largest element (or NULL for n == 0) and returns 0 or -1. In main, use the returned pointer to double the maximum IN the array. Then write, as a comment, three bugs this design avoids or could suffer from (NULL out, empty array, dangling pointer if the array goes out of scope).

Quick quiz

Question 1

1.What usually happens when a program dereferences NULL on Linux?

Question 2

2.What is a dangling pointer?

Question 3

3.Why would a function take int **pp?

Question 4

4.int *a[3]; declares…

Read more (free)

Before this, learn

This topic builds on these. If something here feels new, open them first.

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What usually happens when a program dereferences NULL on Linux?

Answer: A segmentation fault

Address 0 is not mapped.

What is a dangling pointer?

Answer: A pointer to memory that was freed or went out of scope

Using it is undefined behaviour.

Why would a function take int **pp?

Answer: To change which address the caller's int * holds

It needs the address of the pointer.

int *a[3]; declares…

Answer: An array of 3 pointers to int

[] binds tighter than *.

How should a pointer be printed with printf?Related

Answer: %p with a (void *) cast

%p expects a void pointer.

From Addresses and pointers

Returning &local from a function gives…Related

Answer: A dangling pointer to memory that is no longer valid

The local variable is gone after return.

From Pointers and functions

Where does an array NOT decay to a pointer?Related

Answer: In sizeof a

sizeof (and &a) see the whole array.

From Pointers and arrays

What is the zero value of a pointer?Related

Answer: nil

An unset pointer is nil.

From Pointers without fear

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Pointers”. The module exam comes next.
  2. Module 5 exam: Pointers · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Dynamic memory. 60 topics left in the course before the final exam.

← Previous: Pointer arithmetic