A pointer is a value that represents the address of an object or location in memory.
Learning Question
What does a C pointer become at the machine level?
In C, pointer syntax can look special:
int value = 10;
int *p = &value;
*p = 20;At the source level, p is a pointer to int.
At the machine level, the value stored in p is an address value.
That address value can be used by generated instructions to access memory.
The first mental model is:
A pointer is not the object it points to. A pointer is a value that tells the program where an object can be accessed.
Pointer Value and Pointed-To Object
Two things must be kept separate:
| Concept | Meaning |
|---|---|
| pointer value | an address value |
| pointed-to object | the object stored at that address |
In this code:
int value = 10;
int *p = &value;value is an int object.
p is a pointer object whose value is the address of value.
The pointer and the pointed-to object are not the same storage.
Changing p changes which address the pointer holds.
Changing *p changes the object at the address held by p.
The Address-Of Operator
The expression:
&valuemeans:
produce the address of
value
At the machine level, this requires the generated code to compute or obtain an address.
For a local variable stored in a stack frame, the address may be calculated relative to the frame base.
A simplified x86-64-shaped example is:
leaq -4(%rbp), %raxConceptually, this means:
compute the address of the stack location at -4(%rbp), and put that address in %raxThe instruction does not load the integer value stored at -4(%rbp).
It computes the address of that location.
That distinction is central to pointers.
The Dereference Operator
The expression:
*pmeans:
access the object at the address stored in
p
If the program writes:
*p = 20;the generated code must:
- read the address value stored in
p - use that address to access memory
- store
20into that memory location
A simplified x86-64-shaped sequence is:
movq -16(%rbp), %rax
movl $20, (%rax)Conceptually:
load the pointer value from p into %rax
store 20 into the memory location whose address is in %raxThe notation (%rax) means memory at the address held in %rax.
That is indirect memory access.
Pointer Variables Still Need Storage
A pointer variable is still a variable.
It may itself be stored in memory, held in a register, or optimized away as a separate location.
For example:
int *p = &value;may be represented in unoptimized code by storing an address value into a stack slot used for p:
leaq -4(%rbp), %rax
movq %rax, -16(%rbp)The first instruction computes the address of value.
The second instruction stores that address into the stack location used for p.
This shows another important separation:
| Source-Level Thing | Possible Machine-Level Representation |
|---|---|
value | an int stored at a memory location |
&value | the address of that memory location |
p | storage containing that address value |
*p | access to memory at the address stored in p |
The pointer object has storage.
The pointed-to object has storage.
The pointer’s stored value connects them.
Pointer Type Gives Meaning to the Address
At the machine level, an address is a numeric value used to locate memory.
At the C level, a pointer has a type:
int *p;
char *s;
double *d;The pointer type matters because it tells C how to interpret operations through that pointer.
For example, the type affects:
- what kind of object
*prefers to - how many bytes are read or written for
*p - how pointer arithmetic scales
- what assignments are type-correct
The address value alone does not carry all that source-level meaning.
The C type system gives the pointer expression its interpretation.
The generated instructions must implement behavior consistent with that interpretation.
Pointer Arithmetic Means Address Calculation
Consider:
p + 1If p has type int *, then p + 1 means the address of the next int, not the next byte.
If an int is 4 bytes on the target platform, then adding 1 to an int * usually corresponds to adding 4 bytes to the address value.
Conceptually:
p + 1 means address(p) + sizeof(*p)This is why pointer type matters.
The same numeric address operation is not chosen only from the + 1 text.
It depends on the pointed-to type.
Arrays and structs make this address-calculation idea more visible in the next chapter.
Pointers Do Not Include Bounds by Themselves
A pointer value tells the program an address.
It does not automatically contain the size of the valid object, the bounds of an array, or a guarantee that the address is safe to use.
For example:
int values[3];
int *p = &values[0];The pointer value can identify the first element.
But a plain C pointer does not by itself remember that the array has exactly three elements.
The programmer and the program logic must preserve correct bounds.
This is one reason pointer bugs can be serious in C.
The machine can use an address value even when the C program’s reasoning about that address is wrong.
Null Pointers
A null pointer is a special pointer value that does not point to a valid object.
In C, it is commonly written as:
int *p = NULL;or:
int *p = 0;The exact machine representation is platform-defined, but the C meaning is clear:
This pointer value is not the address of an object that may be dereferenced.
Using a null pointer as an address for *p is invalid in C.
The important distinction is:
A pointer variable can hold a value that is not safe to dereference.
Being a pointer does not guarantee that dereferencing it is valid.
Pointers and Assembly Questions
When reading assembly for pointer code, useful questions are:
- Which instruction computes an address?
- Which instruction loads a pointer value?
- Which instruction uses a register as an address?
- Is the instruction reading from that address or writing to it?
- How many bytes are being read or written?
For example:
movq -16(%rbp), %rax
movl $20, (%rax)The first instruction loads the pointer value.
The second instruction stores through that pointer value.
The parentheses around %rax mark a memory access through an address held in the register.
That is the machine-level counterpart of C dereference syntax.
What This Chapter Does Not Explain Yet
This chapter explains pointers as address values.
It does not yet fully explain:
- arrays as repeated elements
- struct field offsets
- pointer aliasing rules
- ownership and lifetime bugs
- dynamic allocation with
malloc - virtual memory
- segmentation faults in detail
- every addressing mode in assembly
Those topics build on the same foundation:
Pointer operations are operations on address values and memory access through those address values.
Core Mental Model
Keep these boundaries separate:
- A pointer object is storage whose value is an address.
- The pointed-to object is the object located at that address.
&xproduces the address ofx.*paccesses memory at the address stored inp.- Pointer type gives C-level meaning to dereference and pointer arithmetic.
- A pointer value does not automatically carry bounds or validity guarantees.
- Assembly helps reveal when code computes an address, stores an address, loads through an address, or writes through an address.
When reading pointer code, ask:
Is this expression working with the pointer value itself, or with the object at the address stored in the pointer?
Final Summary
A C pointer is best understood as an address value with a type.
The address value tells generated instructions where memory can be accessed.
The type tells the C program how operations through that address should be interpreted.
Assembly makes pointer behavior concrete by showing address calculation, pointer-value movement, and memory access through registers holding addresses.