Pointers and References to Structures
A struct member can be accessed through the struct's name, a reference to the struct, or a pointer to the struct.
Try it: Names and Objects
How Python variables are names bound to objects: assignment never copies, mutating a list is seen through every name that points at it, and ints are replaced rather than changed.
How it works
- name = object binds a name; b = a makes b point at the same object.
- Mutating a list (append, +=) changes the one shared object.
- a = a + [x] and y = y + 1 create NEW objects and re-point one name.
- Passing a list to a function passes the reference, so the function can change it.
Default run (7 steps): Two names, one list. Every name is a label that points at an object. … Printed: [1, 2, 3] / True
Simplified: Six fixed scripts on a tiny heap; you choose the values. Object numbers are illustrative, not real id() values.
Loading the simulation…
Predicting Which Operator to Use
Suppose a function receives a Vector in three different forms: as a plain value, as a reference, and as a pointer. Each form gives the function a different kind of handle on the same struct. The function needs to read the member sz from each handle. The question is simple to state: given that you hold a Vector in one of these forms, how do you get at its sz member?
What do you think happens?
Of the three reads v.sz, rv.sz, and pv->sz, which one goes through a pointer, and which operator does it use?
Reveal answer
pv->sz is the access that goes through a pointer, and it uses the arrow operator. v.sz and rv.sz both use the dot operator.
The first two reads use the dot because v is the struct itself and rv is a reference, which is another name for the same object. The third read uses the arrow because pv holds the location of a Vector rather than the Vector. Only the operator changes; the member name sz is written the same way after it.
Three Handles on the Same Member
A struct member can be accessed in three ways, depending on what you hold. You can access it through the struct's name, which means you have the struct object itself. You can access it through a reference to the struct, which is another name for the same object. Or you can access it through a pointer to the struct, which holds the location of the object rather than the object itself.
A reference to a struct is another name for the same object, so a member reached through a reference is the same member of the same object that the struct's name reaches. A pointer to a struct holds the location of the object rather than the object itself, so reaching a member through a pointer requires following that location first.
All three routes lead to the same member. The difference lies in how you reach the object, not in what the member is. The member sz is one int inside a Vector, and it is the same sz whether you arrive through the name, the reference, or the pointer.
Tracing a Function That Takes Three Forms
The clearest way to see the three routes is to watch one function read sz through each of them. The example below is an illustrative reconstruction in the same shape as the trace this lesson uses. It takes a Vector by value, by reference, and by pointer, and it reads sz from each parameter into a separate int variable.
- The parameter v is a plain value, so v.sz uses the dot operator.
- The parameter rv is a reference, which is another name for the caller's object, so rv.sz also uses the dot.
- The parameter pv holds the location of a Vector, so pv->sz uses the arrow.
Deciding Which Read Uses Which Operator
For each of the three reads in read_three, decide which operator is written and explain why that operator is valid for that handle.
- 1Read v.sz
v is the Vector itself, held as a plain value. The struct name gives direct access to the object, so the dot operator is used.
- 2Read rv.sz
rv is a reference, which is another name for the same object. Because it refers to the object directly, rv.sz is written with the dot, just like v.sz.
- 3Read pv->sz
pv holds the location of a Vector rather than the Vector. The arrow operator follows that location to the object and then reaches sz, so pv->sz is written with the arrow.
- 4Compare the results
The three int variables receive the value of the same member. The punctuation differs only because the handles differ.
v.sz and rv.sz use the dot operator; pv->sz uses the arrow operator. All three read the same sz member of the Vector.
Notice that the function reads sz but does not change it. Each of these reads only copies a value into an int. Whether the caller's original struct is affected by the function depends on how the parameter was passed. The v parameter is a plain value, so the function works with its own copy of the struct, while rv and pv give the function access to the caller's object.
Choosing Between Dot and Arrow
The two operators correspond to the two kinds of handle. The dot operator is used when you access members through a struct's name or through a reference. The arrow operator is used when you access members through a pointer to a struct. The member name is written after the operator in both forms. Only the operator changes, and the operator tells you what kind of handle you are holding.
The arrow is a shorthand. Writing pv->sz means the same thing as first dereferencing the pointer to reach the object and then using the dot on it. The parenthesized form makes the dereference step visible, and it is the same member in both cases.
- The arrow hides the dereference step inside the operator.
- The parentheses are required in the long form so that the dereference happens before the member is selected.
Reference Versus Pointer Side by Side
A reference and a pointer can both be used to reach the same struct's members, so it is easy to confuse them. The table below separates what each one is, how each one is accessed, and what each one can do.
| Feature | Reference | Pointer |
|---|---|---|
| What it is | Another name for the same struct object | Holds the location of the struct object |
| How a member is reached | Dot operator, as in rv.sz | Arrow operator, as in pv->sz |
| Can it be changed to refer to something else | No, once bound it stays the same object | Yes, a pointer can be reassigned to point elsewhere |
| Needs following a location first | No | Yes, the arrow follows the stored location |
How a reference and a pointer differ when both reach the same struct's members
Mistakes When Picking an Operator
Common mistake Using the dot on a pointer
What it looks likepv.sz when pv is a pointer to a Vector
Why it failsThe dot operator is used for access through a name or a reference. A pointer holds a location, not the struct, so the dot does not reach the member through it.
Do this insteadWrite pv->sz, because the arrow is the operator for access through a pointer to a struct.
Common mistake Using the arrow on a struct name or reference
What it looks likev->sz when v is a Vector, or rv->sz when rv is a reference
Why it failsThe arrow is used for access through a pointer. v and rv are the struct and its alias, not a pointer to it, so the arrow does not match the handle held.
Do this insteadWrite v.sz and rv.sz with the dot.
Common mistake Assuming all three reads are different members
What it looks likeBelieving v.sz, rv.sz, and pv->sz each read a different field
Why it failsAll three routes lead to the same member. Only the way of reaching the object differs.
Do this insteadRead the expressions as three handles on one sz member, and pick the operator that matches the handle.
Common mistake Forgetting that the member name is written the same way after either operator
Trace Another Function
A function takes a Vector by reference as rv and a Vector by pointer as pv. It writes int a = rv.sz; and int b = pv->sz;. Without running the code, state which operator each line uses, and explain whether a and b read the same member. Then say what changes in your answer if the parameter is changed from a pointer to a plain value written as v, with the line int c = v.sz;.
Hints
- Ask first what each handle holds: the object itself, another name for it, or a location.
- Only the operator is different between rv.sz and pv->sz. The member name sz is the same.
- A plain value v also holds the struct itself, so its member is reached with the dot.
Key Takeaways
- A struct member can be reached through the struct's name, through a reference to the struct, or through a pointer to the struct, and all three routes lead to the same member.
- The dot operator is used with a struct's name or a reference, as in v.sz and rv.sz, while the arrow operator is used with a pointer to a struct, as in pv->sz.
- A reference is another name for the same object, while a pointer holds the location of the object, so reaching a member through a pointer requires following that location.
- Pick the operator by asking what handle you hold: the struct or its reference takes the dot, and a pointer takes the arrow.
- The arrow is shorthand for dereferencing the pointer and then using the dot, so pv->sz and (*pv).sz name the same member.