Array and Pointer Basics
The prefix unary ampersand means address of. Applied to an object such as v[3], it produces that object's address, which a pointer can hold.
Predicting What a Pointer Leads To
A pointer is useful only if you can move in two directions: from an object to its address, and from a pointer back to the object it points to. This article is about those two moves. Each one is a prefix unary operator, meaning it sits directly in front of the single operand it acts on. The ampersand goes from an object to its address. The asterisk goes from a pointer to the object it points to.
What do you think happens?
Suppose v is an array and p holds the address of its fourth element, v[3]. What does the expression that applies the prefix asterisk to p produce?
Reveal answer
The object that p points to, which is v[3] and its stored value
The prefix asterisk means contents of. Applied to a pointer, it gives the object that the pointer points to. Here that object is the fourth element of v. Commit to your answer, because the next sections check your reasoning.
Getting an Address with the Ampersand
The prefix unary ampersand means address of. Applied to an object such as v[3], it produces that object's address, which a pointer can hold.
The result of the ampersand is an address, not the element's value. The address-of operator answers the question 'where is this object?' It does not answer 'what is stored in this object?' Keeping those two questions apart is the main skill this article builds.
In the source's example, applying the ampersand to v[3] yields the address of the fourth element of v. A pointer declaration such as the one below is read as 'p is initialized to the address of v[3]'. The declaration gives p a target. It does not copy the element anywhere.
- &v[3] produces the address of the fourth element of v
- p receives that address as its value
- The element v[3] is not copied or changed
Tracing an Address and Its Target
Now follow the operations one at a time. Start with the declaration that stores the address of v[3] in p. Then apply the prefix asterisk to p and watch what object each step refers to. The diagram below shows the path. The pointer p reaches the fourth element, and the value read through p is what gets copied into x.
Following p = &v[3] and then reading through p
Given an array v and the statements below, state the object each expression refers to and what it produces.
- 1Step 1: evaluate &v[3]
The ampersand is applied to the object v[3]. The result is the address of the fourth element. It is an address, so it is the right kind of value to store in a pointer.
- 2Step 2: store the address in p
The declaration gives p the address of v[3] as its value. p now refers to v[3]. Nothing has been copied out of v[3] yet.
- 3Step 3: evaluate *p
The asterisk is applied to the pointer p. The object p points to is v[3], so the expression refers to v[3] itself and gives access to the value stored there.
- 4Step 4: assign the value to x
The value read through p is what x receives. p still holds the same address after this step, because reading through a pointer does not change the pointer or the object it refers to.
The address-of step refers to v[3] and produces its address. The dereference step refers to v[3] again and produces its stored value, which x receives. p is unchanged.
Reading Through a Pointer
The prefix unary asterisk means contents of. Applied to a pointer such as p, it gives the object that the pointer points to.
Dereferencing is the step that moves from the pointer back to the value it leads to. In the source's initialization, a variable x is set from the object p points to. The source phrases it this way: the object that p points to is written as the prefix asterisk applied to p.
- *p applies the asterisk to the pointer p
- The object p points to is v[3] in this lesson's setup
- x is set from that object's value
Two Operators in One Expression
Both operators are prefix unary operators, and they point in opposite directions. The same written form can therefore mean very different things depending on what follows it. A useful check for any expression is to ask what kind of thing the operator acts on. An object goes into the ampersand and an address comes out. A pointer goes into the asterisk and an object comes out. If you apply an operator to the wrong kind of operand, the expression no longer means what you intended.
Reading *&v[3] from the inside out: the ampersand acts on v[3] and produces its address. The asterisk then acts on that address and gives back the object at that address, which is v[3]. The two operations undo each other, so the whole expression refers to v[3]. The inner operator applies first, which is why evaluating the expression from left to right on the page can mislead you.
| Operator | What it acts on | What it produces | Question it answers |
|---|---|---|---|
| Prefix ampersand (address of) | An object such as v[3] | The address of that object | Where is this object? |
| Prefix asterisk (contents of) | A pointer such as p | The object the pointer points to | What is stored in the object the pointer leads to? |
The two prefix unary operators side by side
Mistakes Beginners Make with the Two Operators
Common mistake Reading the ampersand as if it returns the element's value
What it looks likechar *p = &v[3]; is read as 'p gets the value of v[3]'.
Why it failsThe ampersand produces an address. It answers where the object is, not what is stored in it.
Do this insteadRead the declaration as 'p is initialized to the address of v[3]'. The element itself is not copied.
Common mistake Assuming the asterisk changes the pointer
What it looks likeAfter char x = *p;, believing that p now points somewhere else.
Why it failsReading through a pointer does not change the pointer or the object it refers to.
Do this insteadAfter the read, p still holds the same address. Only the value of x changed.
Common mistake Applying the operators in the wrong order or to the wrong kind of operand
What it looks likeTreating *&v[3] as if the asterisk acted on v[3] before the ampersand did.
Why it failsThe inner operator applies first. The ampersand needs an object, and the asterisk needs a pointer.
Do this insteadCheck the operand type at each step: the ampersand takes an object and gives an address, and the asterisk takes a pointer and gives an object.
Common mistake Confusing the output of a copy loop because the pointer and the object it refers to were mixed up
Why This Matters for Copying Array Elements
The source introduces these operations with a practical goal: copying ten elements from one array to another. Once a pointer can reach an element and that element's contents can be read through the pointer, the program can work on array elements through pointers instead of naming each element directly. The example below is an illustration of that idea and is not taken from the source.
- ps and pd each hold the address of one element
- x receives the value read through ps
- Writing through pd stores the value into dst[3]
Practice Tracing Pointer Operations
Given an array v and the statements char *p = &v[3]; char x = *p; state, for each of these expressions, the object it refers to and what it produces: (a) &v[3], (b) p, (c) *p, (d) *&v[3].
Hints
- For (a), the ampersand acts on an object and produces an address.
- For (b), p is a pointer variable, and it holds an address.
- For (c), the asterisk acts on the pointer p and gives the object p points to.
- For (d), work from the inside out: the ampersand acts first, then the asterisk undoes it.
Key Takeaways
- The prefix unary ampersand means address of. Applied to an object such as v[3], it produces that object's address, which a pointer can hold.
- The prefix unary asterisk means contents of. Applied to a pointer such as p, it gives the object that the pointer points to.
- Reading through a pointer does not change the pointer or the object it refers to, so p keeps pointing at the same place.
- Check the operand type at each step: an object goes into the ampersand and an address comes out, and a pointer goes into the asterisk and an object comes out.
- These two operations are the basis for working with individual array elements through pointers, including tasks such as copying elements from one array to another.