5.1.12 · D3C Programming

Worked examples — Pointer to pointer

3,508 words16 min readBack to topic

This is the drill floor for Pointer to pointer. The parent note taught you what int ** is and why dereference "peels a layer." Here we hit every case class that pointers-to-pointers can throw at you — normal chains, broken chains (NULL), function calls that must reach back, string arrays, dynamic memory, and the classic exam traps — and we work each one until nothing surprises you.

Figure 1 (below) — the master picture for the whole page. It shows the three linked boxes pp → p → x laid out left to right. The takeaway to burn in: pp on its own is zero walks (holds 0x200), one black arrow (*pp) reaches p (holds 0x100), and the second arrow — drawn in red to the treasure box — is what **pp reaches: the value 42. Two of the three names are addresses; only the red-highlighted end is the actual number.

Figure — Pointer to pointer

The scenario matrix

Every problem in this topic lands in one of these cells. The worked examples that follow each carry a [Cell …] tag so you can see the whole grid is covered.

Cell Case class What makes it tricky Example
A Normal chain read (pp → p → x) count arrows correctly Ex 1
B Writing at each level (*p, then **pp, then *pp) which link you overwrite Ex 2
C Broken chain (p == NULL) **pp crashes; *pp is fine Ex 3
D Function changes caller's pointer pass &q, use int ** Ex 4
E Dynamic memory via int ** malloc result escapes the function Ex 5
F Array of strings (char **) *pp = string, **pp = one char Ex 6
G Pointer arithmetic on ** pp+1 steps by sizeof(pointer) Ex 7
H Degenerate / self-reference twist pointer to itself, re-aiming a link Ex 8
I Exam trap: count-the-stars output predict exact printed number Ex 9

Note on Cell B: the three notations are listed in the exact order Example 2 executes them — first *p (line 1), then **pp (line 2), then *pp (line 3) — so you can follow the table and the example line-for-line.

We will assume this concrete memory layout throughout (invented but consistent addresses, so every "Verify" is checkable):


Example 1 — Read the whole chain [Cell A]

So: pp = 0x200, *pp = 0x100, **pp = 42.


Example 2 — Write at each level [Cell B]

Figure 2 (below) — the same three lines drawn on the chain. The p box is drawn in red because it is the link that Line 3 re-aims: the picture shows *p = 20 and **pp = 30 both arriving at the x box (same destination, two routes), while *pp = NULL stops one box short and overwrites the red p box itself. Takeaway: trace where each red/black arrow ends — that is the box you overwrote.

Figure — Pointer to pointer

Example 3 — The broken chain [Cell C]


Example 4 — Function changes the caller's pointer [Cell D]


Example 5 — Dynamic memory escaping via int ** [Cell E]


Example 6 — Array of strings [Cell F]

Figure 3 (below) — the string array drawn as two columns. Left column is the char* array (names[0..2]), right column is the actual text of each string; the red highlight marks names[0] and its string "Ann", which is the target of *pp and (one more step) **pp. Takeaway: one arrow lands in the right column on a whole word (a char*), and only a second step into the letters of that word gives you a single char — that is why *pp prints Ann but **pp prints A.

Figure — Pointer to pointer

Example 7 — Pointer arithmetic on int ** [Cell G]



Example 9 — Exam trap: count the stars [Cell I]


Recall Cover-and-recall: which cell is which?

Ann/Bo/Cy string array — which cell? ::: F (array of strings, char **) *pp = NULL overwriting the pointer — which cell? ::: B (writing at a level) redirect(&q, &b) changing main's pointer — which cell? ::: D (function changes caller's pointer) **pp crashing because p is NULL — which cell? ::: C (broken chain) (*pp)++ moving a pointer not a value — which cell? ::: I (count-the-stars exam trap)


Connections

  • Pointer to pointer (index 5.1.12) — the parent concept this drills.
  • Pointers basics — single-level reads/writes underlie every step.
  • Pass by value vs pass by reference — Example 4's whole reason to exist.
  • Dynamic memory allocation (malloc) — Example 5's int ** return pattern.
  • Command line arguments (argv) — Example 6 is char **argv in miniature.
  • Pointer arithmetic — Examples 6, 7, 9 hinge on +1 stepping by the pointed-to size.
  • 2-D arrays vs pointer to pointer — Example 7's int *row[] vs a true 2-D array.