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 thataandbpoint to.doubleAll(values: []i32) void--- doubles every element in the slice in place.