How the Dereference Operator Works in C

This article explains how the dereference operator (*) retrieves data from memory in the C programming language. It covers the relationship between pointers and physical memory addresses, the critical role a pointer's data type plays in determining how many bytes are read, and the low-level machine instructions executed by the CPU to load that stored data into a usable variable.

In the C programming language, computer memory (RAM) is treated as a linear sequence of sequentially numbered byte cells, each possessing a unique memory address. A pointer variable does not hold standard application data directly; instead, it stores one of these numerical memory addresses. The dereference operator, denoted by the asterisk symbol (*), instructs the compiler to bypass the pointer's own location and directly access the contents held at the memory address the pointer contains.

To retrieve data successfully, the dereference operator relies on two critical pieces of information: the starting memory address and the data type of the pointer. The address identifies where the data begins in memory. The data type tells the compiler two things: how many contiguous bytes to read from that starting point, and how to interpret the resulting binary pattern (such as an integer, a floating-point number, or an ASCII character).

For example, consider the following operation:

int value = 42;
int *ptr = &value;
int retrieved = *ptr;

When *ptr is evaluated, the retrieval process occurs in defined steps:

  1. Address Resolution: The runtime evaluates ptr to get the raw numerical memory address it holds (the address of value).
  2. Byte Count Determination: Because ptr is declared as an int *, the compiler knows that a standard integer typically occupies 4 bytes on modern architectures.
  3. Memory Fetch: The CPU issues a memory read request starting at the address stored in ptr and reads the next 4 consecutive bytes.
  4. Type Interpretation: The retrieved 4-byte sequence of bits is interpreted as a signed two's-complement integer and copied into the destination variable retrieved.

At the hardware level, dereferencing translates directly into assembly load instructions using indirect addressing modes. On an x86-64 architecture, this is commonly handled by a mov instruction (such as mov eax, [rdi]), where the brackets denote that the CPU should fetch the contents stored at the address contained in the register, rather than using the register's literal value.

Because dereferencing blindly reads memory based strictly on the address provided, attempting to dereference an invalid, uninitialized, or NULL pointer causes undefined behavior, often resulting in a segmentation fault when the operating system blocks the illegal memory access.