LESSON 05 · BEGINNER4 min read

Raw Pointers, Dereferencing, and Typed Address Arithmetic

Deconstruct pointer mechanics: 64-bit addresses, dereferencing indirection (*), address-of (&), pointer scaling rules, and void* type erasure.

C++20 / C++23Free to readModule 2 of 11
YOUR NEXT SMALL WINS

By the end, you’ll be able to…

  • Inspect 64-bit virtual memory addresses using uintptr_t and hex formatting
  • Calculate pointer arithmetic jumps scaled by sizeof(T) across primitive and struct types
  • Manipulate untyped raw memory blocks using void* and reinterpret_cast

01Pointers as 64-Bit Memory Addresses

In modern 64-bit C++, a raw pointer is nothing more than an 8-byte unsigned integer value whose bits represent an address in the process's virtual memory space. Regardless of whether a pointer points to a 1-byte char, a 4-byte int, or a 1024-byte struct, sizeof(ptr) is universally 8 bytes on 64-bit architectures.

The address-of operator (&) extracts the memory location of an existing variable. The dereference operator (*) instructs the CPU to load or store the data residing at that memory address. Dereferencing an uninitialized pointer (wild pointer), a dangling pointer (pointing to freed memory), or a NULL/nullptr pointer results in undefined behavior (UB) and operating system segmentation faults.

Modern C++ deprecates the C-style NULL macro (which was merely an untyped 0) in favor of nullptr, a strongly typed keyword of type std::nullptr_t that prevents ambiguous overload resolutions between integers and pointers.

example.js⚙️C++
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

02Pointer Arithmetic and Type Scaling

Pointer arithmetic does not behave like standard scalar integer addition. When you add an integer offset n to a typed pointer T* p (e.g., p + 1), the memory address increases not by n bytes, but by n * sizeof(T) bytes!

For example, if int* p points to address 0x1000 (where sizeof(int) == 4): evaluating p + 1 advances the pointer to 0x1004. Evaluating p + 5 advances the pointer to 0x1000 + (5 * 4) = 0x1014. If double* dp points to 0x2000 (sizeof(double) == 8), evaluating dp + 2 advances to 0x2010.

This scaling rule ensures that pointer arithmetic seamlessly steps across contiguous elements in arrays. Subtracting two pointers (ptr2 - ptr1) yields an integer of type ptrdiff_t representing the exact count of elements between them.

03Void Pointers and Raw Byte Buffers

A void* pointer represents a generic memory address with no associated type information. Because the compiler does not know the size of the underlying data (sizeof(void) is invalid in standard C++), a void* cannot be directly dereferenced and arithmetic cannot be performed on it without casting.

Systems software—such as custom memory allocators, network serialization engines, and hardware drivers—uses void* or std::byte* to handle raw, untyped memory buffers. Converting between void* and concrete typed pointers is performed via static_cast or reinterpret_cast.

04Pointer Arithmetic Trace Table

Let us trace address jumps across different types starting from a base address of 0x1000:

Understanding pointer scaling is foundational for writing custom buffers, matrix strides, and fast memory copies.

notes.txtPlain text
+------------+-----------+--------------------+-------------------------+| Type T     | sizeof(T) | Expression (p = 0) | Resulting Byte Address  |+------------+-----------+--------------------+-------------------------+| char       | 1 byte    | p + 4              | 0x1000 + 4 = 0x1004     || short      | 2 bytes   | p + 4              | 0x1000 + 8 = 0x1008     || int        | 4 bytes   | p + 4              | 0x1000 + 16 = 0x1010    || double     | 8 bytes   | p + 4              | 0x1000 + 32 = 0x1020    || struct Vec3| 24 bytes  | p + 2              | 0x1000 + 48 = 0x1030    |+------------+-----------+--------------------+-------------------------+
LET IT CLICK

The ideas worth keeping.

  • Pointers are 64-bit virtual memory addresses that require 8 bytes of storage on 64-bit systems.
  • Pointer arithmetic automatically scales offsets by sizeof(T).
  • Always use nullptr rather than 0 or NULL to ensure strict type safety.
TURN UNDERSTANDING INTO SOMETHING YOU CAN DO

Make it yours.

Type and test your code right here in the interactive workspace. Run your solution, check the output, and compare with the worked guide when ready.

01

Exercise 1: Given a struct Packet uint32 t id double p

Given a struct Packet { uint32_t id; double payload[4]; }; with sizeof(Packet) == 40 bytes, calculate the resulting address when adding 3 to Packet* ptr starting at 0x2000.

your_turn_1.cpp⚙️C++
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.cppC++
// Pointer arithmetic formula: Address = Base + (Offset * sizeof(T))// Address = 0x2000 + (3 * 40 bytes)// 3 * 40 = 120 bytes = 0x78 in hexadecimal// Resulting Address = 0x2078

Multiply offset 3 by 40 bytes, then convert to hexadecimal.

02

Exercise 2: Explain why standard C forbids pointer arit

Explain why standard C++ forbids pointer arithmetic on void* pointers, and how to safely compute byte offsets.

your_turn_2.cpp⚙️C++
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.cppC++
// void is an incomplete type with no size (sizeof(void) is undefined),// so the compiler cannot determine how many bytes to scale the pointer by.// To safely perform byte arithmetic, cast void* to char* or std::byte*:// void* offset_ptr = static_cast<std::byte*>(raw_buffer) + byte_offset;

Cast the pointer to std::byte* or char* before adding the offset.

A SMALL QUESTION. A USEFUL NEXT STEP.

What stayed with you?

Check the ideas while they’re fresh. Your answers stay in this page and feedback appears as you go.

A LITTLE ACTIVE RECALL0 / 3 answered
01What is the size of a raw pointer (int* or double*) on a 64-bit operating system?
02If int* p points to address 0x1000 and sizeof(int) is 4, what address does p + 2 point to?
03Why is nullptr preferred over the C macro NULL in modern C++?
⚡CODING CHALLENGE
🔒Required to Mark Lesson Complete

Exercise 1: Given a struct Packet uint32 t id double p

Given a struct Packet { uint32_t id; double payload[4]; }; with sizeof(Packet) == 40 bytes, calculate the resulting address when adding 3 to Packet* ptr starting at 0x2000.

EXPECTED OUTPUT
Build completed. Binary executed.
[Exit code: 0]
main.cppC++
Ctrl + ↵
Execution Console
Click "Run & Verify" (or press Ctrl + Enter) to test your code against the challenge.

Keep exploring.

The official references behind this lesson, when you want a second angle or the full details.

One lesson closer.

Reading is a start. Trying it yourself makes the connection.

Solve the hands-on coding challenge in the knowledge section to verify your code and unlock lesson completion.