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:

ConceptMeaning
pointer valuean address value
pointed-to objectthe 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:

&value

means:

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), %rax

Conceptually, this means:

compute the address of the stack location at -4(%rbp), and put that address in %rax

The 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:

*p

means:

access the object at the address stored in p

If the program writes:

*p = 20;

the generated code must:

  1. read the address value stored in p
  2. use that address to access memory
  3. store 20 into 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 %rax

The 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 ThingPossible Machine-Level Representation
valuean int stored at a memory location
&valuethe address of that memory location
pstorage containing that address value
*paccess 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 *p refers 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 + 1

If 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.
  • &x produces the address of x.
  • *p accesses memory at the address stored in p.
  • 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.