Lesson 10 of 15

Pointers

Direct Memory Access with Pointers

Zig gives you direct control over memory through pointers. Unlike C, Zig's pointer system is designed with safety in mind: there are no null pointers for single-item pointers, pointer arithmetic is explicit, and the type system distinguishes between mutable and immutable access.

Single-Item Pointers

The type *T is a pointer to a single value of type T. You get a pointer to a variable using the & operator, and you dereference it with .*:

var x: i32 = 42;
const ptr: *i32 = &x;

// Read through the pointer
const value = ptr.*;  // 42

// Write through the pointer
ptr.* = 100;
// x is now 100

Note the .* syntax for dereferencing. This is different from C's *ptr. Zig uses a postfix operator to keep the syntax consistent and unambiguous.

"Set coordinates, Mr. Sulu." Pointers navigate to exact memory locations just like warp coordinates --- you need the right address, or you end up somewhere you really did not want to be.

Const Pointers

A *const T pointer allows reading but not writing. You get a const pointer when you take the address of a const variable:

const y: i32 = 10;
const ptr: *const i32 = &y;
const value = ptr.*;  // 10
// ptr.* = 20;  // ERROR: cannot assign to constant

A *T (mutable pointer) can be implicitly coerced to *const T, but not the other way around. This means functions that only need to read data should accept *const T for maximum flexibility.

Passing Pointers to Functions

Pointers let functions modify the caller's data. Without a pointer, Zig passes values by copy:

fn increment(ptr: *i32) void {
    ptr.* += 1;
}

var n: i32 = 5;
increment(&n);
// n is now 6

Pointers and Structs

When you have a pointer to a struct, you access fields the same way. Zig automatically dereferences through the pointer:

const Point = struct { x: i32, y: i32 };

fn moveRight(p: *Point, amount: i32) void {
    p.x += amount;
}

var p = Point{ .x = 0, .y = 0 };
moveRight(&p, 5);
// p.x is now 5

Pointer Arithmetic and Slices

Zig does not allow arbitrary pointer arithmetic on single-item pointers. If you need to work with contiguous memory, use slices ([]T) or many-item pointers ([*]T). This prevents an entire class of bugs common in C programs.

When to Use Pointers

Use pointers when you need to:

  • Modify the caller's data --- the most common use case
  • Avoid copying large values --- passing a pointer is cheaper than copying a large struct
  • Interface with C code --- Zig's C interop uses pointer types

Your Task

Write two functions:

  • swap(a: *i32, b: *i32) void --- swaps the values that a and b point to.
  • doubleAll(values: []i32) void --- doubles every element in the slice in place.
Zig runtime loading...
Loading...
Click "Run" to execute your code.