Exercises — Pointer arithmetic — adding integers to pointers
The one rule we lean on everywhere (from the parent note):
We'll assume the common sizes unless a problem says otherwise: sizeof(char)==1, sizeof(int)==4, sizeof(double)==8, sizeof(short)==2. A picture of the "locker hallway" model to keep in mind:

Level 1 — Recognition
Can you read a pointer expression and say what it means?
Recall Solution L1-A
p points at a[0]. Adding 2 steps two elements forward (not two bytes): p + 2 points at a[2]. Dereferencing gives the value stored there.
Answer: 30.
Recall Solution L1-B
By the array–pointer identity, indexing is just scaled addition then a dereference:
Both *(arr+3) and *(3+arr) are correct because + is commutative. (3[arr] is also legal but that isn't "only * and +".)
Answer: *(arr + 3) and *(3 + arr).
Recall Solution L1-C
Stride for a char* is sizeof(char) = 1 byte. So five steps five bytes.
Answer: 0x2005.
Level 2 — Application
Plug into the rule with real strides and addresses.
Recall Solution L2-A
Stride sizeof(int) = 4. Three steps:
( in hex is 0xC.)
Answer: 0x40C.
Recall Solution L2-B
As a double*, stride is 8:
Cast to char* first, and the stride collapses to 1:
0x1004 lands inside the first double (halfway through its 8 bytes) — usually a bug. See Strings and char pointers.
Answer: d + 4 = 0x1020; ((char*)d)+4 = 0x1004.
Recall Solution L2-C
Offset in bytes bytes.
Answer: offset 10 bytes; address 0x80A.
Level 3 — Analysis
Reason about what breaks, what's legal, and precedence.
Recall Solution L3-A
* binds tighter than +, so *p + 1 parses as (*p) + 1.
*p + 1 = a[0] + 1 = 7 + 1 = 8*(p + 1) = a[1] = 8
They give the same number here by coincidence (), but for different reasons. Change the array to {7, 100, 9} and they diverge: *p+1 = 8 but *(p+1) = 100. See Dereference operator and precedence.
Answer: *p + 1 = 8 (value-plus-one), *(p + 1) = 8 (next element). Same digit, different meaning.
Recall Solution L3-B
p + 4→ the one-past-the-end pointer. Legal to form, illegal to dereference (undefined behavior).p + 5→ past one-past-the-end. Illegal even to form — computing it is already undefined behavior.p - 1→ before the array. Illegal even to form (undefined behavior).
The only "safe zone" for forming is indices 0 through N inclusive; the safe zone for dereferencing is 0 through N-1. See Undefined behavior and bounds.
Answer: p+4 form-legal/deref-UB; p+5 UB to form; p-1 UB to form.
Recall Solution L3-C
p + qis illegal — "address plus address" is meaningless; the standard defines onlypointer ± intandpointer - pointer.q - pis legal and gives the element count between them (typeptrdiff_t): Note: not bytes — the compiler divides the byte difference bysizeof(int). See Pointer subtraction and ptrdiff_t. Answer:p+qillegal;q-p = 3.
Level 4 — Synthesis
Combine the rule with loops and identities to produce answers.
Recall Solution L4-A
p++ is p = p + 1: each iteration advances one int. We read the current element then step forward:
- k=0: read
a[0]=2, sum=2 - k=1: read
a[1]=4, sum=6 - k=2: read
a[2]=6, sum=12 - k=3: read
a[3]=8, sum=20 - k=4: read
a[4]=10, sum=30
After the loop p points at a[5] (one-past-end) — held, never dereferenced. See Arrays decay to pointers.
Answer: sum == 30.

Recall Solution L4-B
p starts at a[2] (value 15). Now use the identity x[y] == *(x+y):
p[2] = *(p + 2) = *(a + 4) = a[4] = 25*(p - 1) = *(a + 1) = a[1] = 102[p] = *(2 + p) = *(p + 2) = 25(commutativity of+)
Answer: p[2] = 25, *(p-1) = 10, 2[p] = 25.
Recall Solution L4-C
Cast to char* gives stride 1, so +12 moves exactly 12 bytes: 0x500 + 12 = 0x50C. Casting back to int*, we ask which element sits at offset 12 bytes: . So it points at a[3].
Because 12 is an exact multiple of 4, we land cleanly on an element boundary (no bug this time).
Answer: &a[3], address 0x50C.
Level 5 — Mastery
Prove, generalize, and reason about strides you must derive yourself.
Recall Solution L5-A
Let the array start at byte address and let . Then:
Pointer subtraction is defined as the byte difference divided by the element size:
The cancels and the divides out — so the result is i - j independent of the stride. For : .
Answer: proven; numeric value 5.
Recall Solution L5-B
The stride for a struct Pt* is sizeof(struct Pt) = 8, not the size of any single field:
p[3] begins at 0x918. Its field y sits after x (an int, 4 bytes) inside the struct, so y is at byte offset 4 within that struct:
Total byte offset from p to p[3].y is .
Answer: p + 3 = 0x918; &p[3].y = 0x91C; offset 28 bytes.
Recall Solution L5-C
Work left to right, tracking the current pointer type because the stride follows the type:
L + 1:Lislong*, stride 8. →0x2000 + 8 = 0x2008.(int*)(...): reinterpret that address as anint*. Address unchanged:0x2008, but stride now 4.... + 1: now anint*, stride 4. →0x2008 + 4 = 0x200C. The lesson: a cast changes the stride of future arithmetic, never the current address. See Multidimensional arrays and pointers where this stride-switching drives row/element navigation. Answer:0x200C.
Recall
Recall What did each level test?
L1 :: reading an expression's meaning (element vs byte).
L2 :: substituting real strides and addresses (watch the hex).
L3 :: precedence, legality/UB, and pointer±pointer rules.
L4 :: loops, the x[y]==*(x+y) identity, and cast-driven byte moves.
L5 :: deriving strides yourself — subtraction proof, struct stride, mixed casts.
Connections
- Arrays decay to pointers
- Pointer subtraction and ptrdiff_t
- sizeof operator
- Strings and char pointers
- Multidimensional arrays and pointers
- Undefined behavior and bounds
- Dereference operator and precedence