Exercises — Pointers — declaration, dereferencing ( - ), address-of (&)
We will use a running memory diagram convention. Look at the picture below once — every later problem reuses this exact street-of-houses layout.

Level 1 — Recognition
Goal: can you read pointer notation and say what each symbol asks for?
Exercise 1.1
Given int x = 8; and int *p = &x;, state in plain words what each of these evaluates to:
&x, p, *p, *(&x).
Recall Solution 1.1
&x→ the address ofx(a house number, e.g.0x1000). Type:int *.p→ the same address — we just copied&xintop, sop == 0x1000.*p→ go to the address inpand read theintthere →8.*(&x)→&makes the address ofx, then*follows it straight back →8(equalsx).
WHY the last two are equal: p holds &x, so *p and *(&x) follow the same address.
Exercise 1.2
For each declaration, say whether the named variable is a pointer or a plain value:
int a; int *b; int *c, d; char *s;
Recall Solution 1.2
int a;→ plainint.int *b;→ pointer to int.int *c, d;→cis a pointer to int, butdis a plain int. The*binds only toc.char *s;→ pointer to char.
WHY d is not a pointer: * attaches to the individual declarator, not the whole line.
Level 2 — Application
Goal: can you predict what code prints?
Exercise 2.1
int x = 5;
int *p = &x;
*p = 20;
printf("%d\n", x);What prints, and why?
Recall Solution 2.1
Prints 20.
p = &xmakesppoint atx.*p = 20says "go top's target and write 20 there".p's target isx.- So
xbecomes20. There is only one house here —pjust names it.
Exercise 2.2
int m = 3, n = 9;
int *p = &m;
int *q = &n;
int t = *p;
*p = *q;
*q = t;
printf("%d %d\n", m, n);What prints?
Recall Solution 2.2
Prints 9 3.
t = *p→ savem's value:t = 3.*p = *q→ writen's value intom's house:m = 9.*q = t→ write saved3inton's house:n = 3. This is exactly the classicswapdone inline through pointers. See Pass by Reference vs Pass by Value.
Exercise 2.3
int a[3] = {10, 20, 30};
int *p = &a[0];
printf("%d %d %d\n", *p, *(p + 1), *(p + 2));What prints?
Recall Solution 2.3
Prints 10 20 30.
pholds the address ofa[0].p + 1does not add 1 byte — it addssizeof(int)bytes (typically 4), landing exactly ona[1]. This is Pointer Arithmetic.- So
*(p+1)=a[1]=20, and*(p+2)=a[2]=30.
Level 3 — Analysis
Goal: can you trace addresses and spot why code behaves a certain way?
Exercise 3.1
Suppose int x lives at address 0x1000 and sizeof(int) == 4. We do:
int x = 42;
int *p = &x;On a 64-bit machine, give: (a) the value of p, (b) sizeof(x), (c) sizeof(p), (d) *p.
Recall Solution 3.1
- (a)
p == 0x1000— it stores the address ofx. - (b)
sizeof(x) == 4—xis anint(4 bytes). - (c)
sizeof(p) == 8—pis a pointer; all pointers on a 64-bit machine are 8 bytes, regardless of what they point at. - (d)
*p == 42— followpto0x1000, read theint.
WHY (b) and (c) differ: sizeof(p) measures the pointer itself, not its target.
Exercise 3.2
void addFive(int n) { n = n + 5; }
void addTen(int *n) { *n = *n + 10; }
int main(void) {
int v = 100;
addFive(v);
addTen(&v);
printf("%d\n", v);
}What prints, and explain the difference between the two functions.
Recall Solution 3.2
Prints 110.
addFive(v)receives a copy of100. It adds 5 to the copy, then the copy is discarded.vinmainis untouched → still100.addTen(&v)receives the address ofv.*n = *n + 10walks back tomain'svand writes110.- So only
addTenchanges the caller.100 + 10 = 110.
This is the whole reason pointers exist as parameters — see Pass by Reference vs Pass by Value.
Level 4 — Synthesis
Goal: can you assemble multiple pointer ideas into one working piece?
Exercise 4.1
Write a function swap3 that rotates three int variables so a→b→c→a. Then trace:
int a = 1, b = 2, c = 3;
swap3(&a, &b, &c); // want a=3, b=1, c=2
printf("%d %d %d\n", a, b, c);Recall Solution 4.1
void swap3(int *a, int *b, int *c) {
int t = *c; // save c's value (3)
*c = *b; // c gets b's value (2)
*b = *a; // b gets a's value (1)
*a = t; // a gets saved c (3)
}Trace with a=1, b=2, c=3:
t = *c→t = 3.*c = *b→c = 2.*b = *a→b = 1.*a = t→a = 3. Result:a=3 b=1 c=2. Prints3 1 2. Because we pass addresses, the changes land onmain's variables.
Exercise 4.2
int a[4] = {5, 10, 15, 20};
int *p = a; // array name decays to &a[0]
p = p + 2; // advance two elements
*p = *p + 100;
printf("%d %d %d %d\n", a[0], a[1], a[2], a[3]);What prints?
Recall Solution 4.2
Prints 5 10 115 20.
int *p = a;→ the array nameadecays to the address ofa[0](Arrays in C).p = p + 2;→ advance two elements (2 ×sizeof(int)bytes) →pnow points ata[2].*p = *p + 100;→a[2]was15, becomes115.- Only
a[2]changes; the rest are untouched →5 10 115 20.
Level 5 — Mastery
Goal: reason about pointers to pointers, NULL safety, and degenerate cases.
Exercise 5.1 — Pointer to a pointer
int x = 7;
int *p = &x;
int **pp = &p;
printf("%d %d %d\n", x, *p, **pp);
**pp = 50;
printf("%d\n", x);What do the two printfs print? Explain **pp.
Recall Solution 5.1
First line prints 7 7 7; second prints 50.
p = &x→ppoints atx.pp = &p→pppoints atp. Soppis a pointer to a pointer (int **).*pp→ followpponce → you reachp(which is an address).**pp→ follow twice → reachx's value →7.**pp = 50→ two hops land onx; write50there. Soxbecomes50. Look at the two-hop chain in the figure below.

Exercise 5.2 — NULL and the degenerate case
int *p = NULL;
if (p != NULL)
printf("%d\n", *p);
else
printf("empty\n");What prints, and what would happen if we removed the if guard?
Recall Solution 5.2
Prints empty.
p = NULL→ppoints at "nowhere" (address 0), a safe sentinel.- The guard
p != NULLis false, so theelseruns → printsempty. - If we removed the guard and wrote
*pdirectly: dereferencing address 0 is illegal → undefined behaviour, almost always a segmentation fault / crash. See NULL and Segmentation Faults.
WHY the guard: always confirm a pointer targets valid memory before *p.
Exercise 5.3 — The inverse identity under pressure
Without running code, argue whether *(&(*p)) equals *p for a valid pointer p. What if p is NULL?
Recall Solution 5.3
For a valid p: *(&(*p)) equals *p.
*pnames the target object (anintyou can read or write).&(*p)asks "what is the address of that object?" → that is justpagain.*ofp→ back to the value →*p. The&and inner*cancel. For NULLp: it breaks.*pfirst tries to access address 0 → crash before any cancellation can "logically" happen. The identity is only safe whenppoints at real memory.
Lesson: algebraic identities on pointers assume a valid pointer; a NULL/dangling pointer voids the guarantee.
Recall wrap-up
Recall Quick self-check — predict before revealing
Level of each hop before you open.
*(p + 1)forint *preads which element? ::: the element oneintfurther on, i.e.p[1].- Why does
addFive(v)leavevunchanged? ::: C copies the argument; the function edits a copy. - How many hops does
**pptake? ::: two (pp → p → value). - What happens on
*pwhenp == NULL? ::: illegal access to address 0 → crash / undefined behaviour.
Connections
- Pointer Arithmetic — the scaling behind
p + n. - Arrays in C — array-to-pointer decay used in 4.2.
- Pass by Reference vs Pass by Value — the L3 copy-vs-address contrast.
- NULL and Segmentation Faults — the L5 degenerate case.
- Dynamic Memory malloc free — pointers to heap memory (next step).
- Strings as char pointers —
char *follow-on drills.