CS210 · Block 2 · Lesson 13

Pointer Arithmetic

Adding to pointers · Type-aware steps · The precedence trio · Array-pointer duality · Pointer subtraction
At a glance: Day two of three pointer lessons. Lesson 12 introduced what a pointer is. Today you put pointers to work: walking through arrays, three look-alike expressions that behave very differently, and the rule that says array notation and pointer notation are the same thing.
Contents
  1. Lesson Objectives
  2. Assigned Readings
  3. Pre-Class Work
  4. Lesson Materials and Overview
  5. In-Class Work
  6. After Class
1. Lesson Objectives

By the end of this lesson, cadets will be able to:

  1. Use pointer arithmetic to traverse an array, recognizing that p + 1 advances the pointer by sizeof(*p) bytes. (Outcome 2)
  2. Apply the array-pointer duality formula a[i] == *(a + i) to read and write code interchangeably in either notation. (Outcome 2)
  3. Predict pointer arithmetic behavior across pointer types, and distinguish *p++, *(p++), and (*p)++. (Outcome 2, 3)
2. Assigned Readings

Complete before class. Today's reading is short but precise; reread anything that does not sit right.

Source Sections Why
Beej-C Chapter 11, sections 11.1 and 11.2 Pointer arithmetic and array-pointer equivalence. Required.
Beej-C Chapter 11, section 11.3 (void pointers) Optional skim. We cover void* formally at Lesson 36 with function pointers.
3. Pre-Class Work
Do this first
Plan on 30 to 40 minutes. Today builds directly on Lesson 12; if pointers still feel foggy, the 5-minute review in step 2 is the most important thing you can do.

Pre-Class Checklist

1
Read Beej-C Chapter 11.1 and 11.2
Read closely. Beej is unusually compact in this chapter. The two ideas you need to internalize:
  • When you add an integer to a pointer, the pointer jumps by sizeof the pointed-to type, not by 1 byte.
  • a[i] and *(a + i) are the same expression. The compiler treats them identically.
2
Refresh your Lesson 12 pointer basics
If any of the following do not feel automatic, take five minutes to revisit the Lesson 12 page before class:
  • What int *p; declares.
  • The difference between &x (address of) and *p (dereference).
  • Why NULL is a valid value for a pointer and what dereferencing it does.
3
Optional: skim Beej 11.3 (void pointers)
Beej introduces void * at the end of this chapter. You can skim it now, but we do not use it until Lesson 36 (Function Pointers). If you are short on time, skip it.
4
Skim the In-Class section below
Two widgets today: a pointer-arithmetic walkthrough and a short duality self-check. Get a feel for what is there; you do not need to use either yet.
4. Lesson Materials and Overview

Today's content is a short list but a deep one. Three rules drive everything: pointers move in units of the type they point to, the precedence of postfix ++ binds tighter than the dereference, and arrays and pointers are interchangeable in expressions. Internalize those three and most of the C standard library starts to make sense.

Jump to
Slides L12 Recap Pointer Arithmetic Type-Aware Steps The Precedence Trio Array-Pointer Duality Pointer Subtraction

Slides

The Lesson 13 deck covers pointer arithmetic, the precedence trio, array-pointer duality, and pointer subtraction. The slides are the spine of the in-class lecture; the walkthrough widget is where you practice each idea by hand.

Open Lesson 13 slides →

Recap from Lesson 12

A pointer is a variable whose value is the address of another variable. int *p = &x; stores the address of x in p. Dereferencing with *p reads or writes the value at that address. Today we ask: what if you do arithmetic on the address itself?

Pointer arithmetic

You can add an integer to a pointer or subtract one from it. The result is a new pointer that has moved through memory. The amount of movement is not what you might expect.

int arr[5] = {11, 22, 33, 44, 55};
int *p = arr; // p points to arr[0], the 11

printf("%d\n", *p); // 11
printf("%d\n", *(p + 2)); // 33 -- two ints past p

p = p + 1; // p now points to arr[1]
printf("%d\n", *p); // 22

Notice the address in p did not increase by 1 byte when we wrote p + 1. It increased by sizeof(int) bytes (4 on our lab machines). The pointer's type is part of its identity; the compiler uses that type to decide how far one step is.

Type-aware steps

The byte distance moved by + 1 depends entirely on the pointer's declared type:

Pointer type Bytes per step Example: if p == 0x1000, p+1 ==
char * 1 0x1001
short * 2 0x1002
int * 4 0x1004
double * 8 0x1008
long * 8 0x1008

This is why pointer arithmetic is useful instead of error-prone: you do not have to remember how big each type is. The compiler handles the multiplication for you. p + n always lands on the n-th element after p, regardless of the underlying type.

The precedence trio: *p++, *(p++), (*p)++

These three expressions look almost identical. Two of them are the same; the third is completely different. Read the precedence callout, then study the table.

Precedence rule that matters
In C's precedence table, postfix ++ sits with () and [] at level 1, the highest. Prefix * (dereference) sits at level 2.
So *p++ always parses as *(p++) — the ++ binds to p, not to *p. To increment what p points to, you must write (*p)++.
Expression Parses as What it does
*p++ *(p++) Reads the value at p, then advances p by one element. The expression's value is the original *p.
*(p++) *(p++) Identical to *p++. The parentheses are documentation, not behavior. Use them when you want a reader to see the precedence at a glance.
(*p)++ (*p)++ Dereferences p first, then increments the value being pointed to. p itself does not move.

Concrete example. Suppose int arr[3] = {10, 20, 30}; and int *p = arr;. Each row below starts fresh from that state:

*p++; // after: arr is {10, 20, 30}; p points to arr[1]
*(p++); // after: arr is {10, 20, 30}; p points to arr[1] (same as above)
(*p)++; // after: arr is {11, 20, 30}; p still points to arr[0]

Array-pointer duality

Here is the formula that ties this lesson together:

a[i]  ==  *(a + i)

The compiler treats these two expressions identically. Both are valid C; you can use either notation on an array, and you can use either notation on a pointer that points into an array. The array name itself acts like a pointer to its first element in most expressions.

int arr[5] = {11, 22, 33, 44, 55};
int *p = arr; // arr decays to &arr[0]; no & needed

arr[2] // 33 -- array notation on an array
*(arr + 2) // 33 -- pointer notation on an array
p[2] // 33 -- array notation on a pointer
*(p + 2) // 33 -- pointer notation on a pointer

There is one important asymmetry. You can modify a pointer; you cannot modify an array variable. p++ works. arr++ is a compile error. The array name is a fixed label for a fixed block of memory; the pointer is a variable that can be aimed anywhere.

This duality is also why functions like strlen(char *s) and strlen(char s[]) are equivalent declarations. When you pass an array to a function, the function receives a pointer to its first element. The length information does not come along; you pass it separately or you put a sentinel like '\0' at the end of the data.

Pointer subtraction

Subtracting an integer from a pointer works like addition: the pointer moves backward by that many elements. More interesting, you can subtract two pointers that point into the same array. The result is the number of elements between them, not the number of bytes.

int arr[5] = {11, 22, 33, 44, 55};
int *start = arr;
int *end = &arr[3]; // points to the 44

printf("%ld\n", end - start); // 3, not 12

The compiler divides the byte difference by sizeof the pointed-to type for you. This is consistent with pointer addition: both operations work in units of elements, not bytes.

Subtracting pointers that do not point into the same array is undefined behavior. The compiler will not stop you, but the result is meaningless.

5. In-Class Work

Three things to do in class. Use the checklist to track your progress.

  • Work through the pointer arithmetic walkthrough below. Twelve guided tasks across five sections: arithmetic basics, type-aware stepping, the precedence trio, array-pointer duality, and pointer subtraction. About 30 minutes.
  • Take the duality self-check. Five questions on the precedence trio, type-aware steps, and array-pointer duality. About 8 minutes.
  • Complete Lab 13: Bullet Trajectory. Auto-graded through GitHub Classroom. Full instructions in the lab repo.

Pointer Arithmetic Walkthrough

Twelve tasks across five sections. Type each C statement at the prompt. The terminal shows what the simulator did; the memory pane shows variables, an array, and an arrow from each pointer to the address it currently points at.

Before you begin

Enter your name. It will appear on the completion screen so you can include it in your screenshot for the Blackboard reflection.

CS210 Lesson 13 · Pointer Arithmetic Walkthrough

Twelve tasks across five sections. The terminal shows what the simulator did; the memory pane shows the array, the pointers, and which cell each pointer currently aims at.
Task 0 of 12
Section 1: Pointer arithmetic basics
Current task
Loading...
Memory
No array yet.
Type the first declaration on the left.
ptrsim>
How this works: This is not a Linux terminal. It is a teaching tool that simulates pointer arithmetic on a small fixed array. The task card tells you what to type; in walkthrough mode only the expected command advances. Mistype twice and the hint button will pulse. After all tasks are complete, free mode unlocks so you can experiment.

Duality Self-Check

Five questions covering the precedence trio, type-aware stepping, and the array-pointer duality formula. Answer each one and click Check to see how you did. The final summary tells you whether you are ready to move on to the lab.

Before you begin

Enter your name. It will appear on the score card so you can include it in your screenshot for the Blackboard reflection.

CS210 Lesson 13 · Duality Self-Check

Five questions covering type-aware stepping, the precedence trio, and array-pointer duality. Pass at 70% or above; below that, take it again after reviewing.
How this works: One question per card. Pick or type your answer and click Submit. Feedback appears, then click Next to move on. Answers lock once submitted, so think before you submit. After all five, you get a score, a completion code, and a per-question recap.
6. After Class
  • Finish Lab 13 if you did not complete it in class. Submit through GitHub Classroom before Lesson 14.
  • Read Beej-C Chapter 5 (review) and Chapter 4 (review) for Lesson 14.
  • Replay the walkthrough in free mode. Try declaring a char * over a different array and see how the byte steps change.
  • Heads up: Quiz 5 at Lesson 14 covers Lesson 12 (Pointers Introduction). Quiz 6 at Lesson 16 covers pointer arithmetic and pass-by-pointer.
Need help? Schedule EI with your instructor. Bring specific code or specific screenshots, and the exact error message or output you do not understand. Specific questions get unstuck quickly.