Intermediate · Pointers · topic 25 of 60 · 30 min
NULL, dangling pointers and pointers to pointers
Explanation
NULL
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
int *p; /* uninitialised: holds a random address */
*p = 5; /* writes to an unknown place: may crash, may silently corrupt memory */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.
int *p;
{
int temp = 10;
p = &temp;
} /* temp's lifetime ends here */
printf("%d\n", *p); /* dangling: undefined behaviour */Pointers to pointers
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 **.
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
| Declaration | Read it as |
|---|---|
| int *p | p is a pointer to int |
| int **pp | pp 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) |
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
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.
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)
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);
Which line is undefined behaviour? 1: int *p = NULL; 2: int *q; 3: if (p) *p = 1; 4: *q = 1;
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
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Pointers and arraysPointers · same module
- Pointers without fearGo Programming (backend and cloud) · Pointers, interfaces and errors
- Strings are char arraysStrings in C
- C interview questionsEmbedded C, system calls and careers
- Pointers, the stack and the heapC++ Programming (modern C++ and DSA) · References, pointers, arrays and strings
- Undefined behaviourBits, undefined behaviour and safety
Questions people ask about this
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
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.
Where does an array NOT decay to a pointer?Related
What is the zero value of a pointer?Related
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
- This is the last topic of “Pointers”. The module exam comes next.
- Module 5 exam: Pointers · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Dynamic memory. 60 topics left in the course before the final exam.