# Single Item Pointers

### Single Item Pointers

A pointer is a value that stores the address of another value.

In Zig, a single item pointer points to exactly one value. Its type looks like this:

```zig
*T
```

Read `*T` as:

```text
pointer to T
```

So:

```zig
*i32
```

means:

```text
pointer to one i32 value
```

And:

```zig
*u8
```

means:

```text
pointer to one u8 value
```

A pointer does not contain the value itself. It contains the location where the value lives.

#### Taking the Address of a Value

Use `&` to get the address of a value.

```zig
pub fn main() void {
    var x: i32 = 10;
    const p = &x;

    _ = p;
}
```

Here:

```zig
var x: i32 = 10;
```

creates an integer value.

```zig
const p = &x;
```

creates a pointer to `x`.

The type of `p` is:

```zig
*i32
```

because `x` is an `i32`.

The expression `&x` means:

```text
the address of x
```

So after this code:

```zig
var x: i32 = 10;
const p = &x;
```

we can think of memory like this:

```text
x: 10
p: address of x
```

The pointer `p` knows where `x` is stored.

#### Reading Through a Pointer

Use `.*` to access the value that a pointer points to.

```zig
const std = @import("std");

pub fn main() void {
    var x: i32 = 10;
    const p = &x;

    std.debug.print("{}\n", .{p.*});
}
```

Output:

```text
10
```

The expression:

```zig
p.*
```

means:

```text
the value pointed to by p
```

This is called dereferencing the pointer.

A pointer itself is an address. Dereferencing follows the address and gives you the value stored there.

#### Writing Through a Pointer

If the pointed-to value is mutable, you can change it through the pointer.

```zig
const std = @import("std");

pub fn main() void {
    var x: i32 = 10;
    const p = &x;

    p.* = 25;

    std.debug.print("x = {}\n", .{x});
}
```

Output:

```text
x = 25
```

This line:

```zig
p.* = 25;
```

does not change the pointer. It changes the value that the pointer points to.

The pointer still points to `x`.

The value of `x` changes from `10` to `25`.

#### The Pointer Can Be Constant While the Value Is Mutable

This detail is important.

```zig
var x: i32 = 10;
const p = &x;
```

Here, `p` is declared with `const`, but you can still write:

```zig
p.* = 20;
```

Why?

Because `const p` means the pointer variable `p` cannot be changed to point somewhere else.

It does not mean the value behind the pointer is immutable.

Think of it like this:

```text
p cannot point to a different value.
p may still modify x, because x is mutable.
```

Example:

```zig
pub fn main() void {
    var x: i32 = 10;
    var y: i32 = 99;

    const p = &x;

    p.* = 20; // ok

    // p = &y; // not ok: p itself is const
    _ = y;
}
```

The pointer binding is constant. The pointed-to value can still be changed.

#### Pointer to Const

Now compare that with this:

```zig
const x: i32 = 10;
const p = &x;
```

Here, `x` is constant. So the pointer cannot be used to modify `x`.

```zig
pub fn main() void {
    const x: i32 = 10;
    const p = &x;

    // p.* = 20; // error
}
```

The type of `p` is not `*i32`.

It is:

```zig
*const i32
```

Read this as:

```text
pointer to a constant i32
```

The pointer lets you read the value, but not modify it.

```zig
const std = @import("std");

pub fn main() void {
    const x: i32 = 10;
    const p = &x;

    std.debug.print("{}\n", .{p.*});
}
```

This is fine because reading is allowed.

Writing is not allowed.

#### Mutable Pointer Variable

Sometimes you want the pointer variable itself to change.

Then use `var` for the pointer binding:

```zig
const std = @import("std");

pub fn main() void {
    var x: i32 = 10;
    var y: i32 = 20;

    var p = &x;
    std.debug.print("{}\n", .{p.*});

    p = &y;
    std.debug.print("{}\n", .{p.*});
}
```

Output:

```text
10
20
```

Here, `p` first points to `x`. Later, it points to `y`.

Because `p` is declared with `var`, the pointer itself can change.

So there are two separate questions:

| Question | Controlled by |
|---|---|
| Can the pointer variable point somewhere else? | `const` or `var` on the pointer binding |
| Can the pointed-to value be changed through the pointer? | whether the pointer is `*T` or `*const T` |

This distinction is central to Zig pointer code.

#### Passing a Pointer to a Function

Pointers are often used when a function needs to modify a value owned by the caller.

Example:

```zig
fn increment(x: *i32) void {
    x.* += 1;
}

pub fn main() void {
    var n: i32 = 10;
    increment(&n);
}
```

The function receives:

```zig
x: *i32
```

That means `x` is a pointer to one mutable `i32`.

Inside the function:

```zig
x.* += 1;
```

modifies the caller’s variable.

After the call, `n` becomes `11`.

Full example:

```zig
const std = @import("std");

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

pub fn main() void {
    var n: i32 = 10;
    increment(&n);

    std.debug.print("n = {}\n", .{n});
}
```

Output:

```text
n = 11
```

Without a pointer, the function would receive a copy:

```zig
fn incrementWrong(x: i32) void {
    var local = x;
    local += 1;
}
```

Changing `local` does not change the caller’s variable.

Use a pointer when the function needs access to the original value.

#### Passing a Pointer for Efficiency

Pointers are also useful when a value is large.

Suppose you have a large struct:

```zig
const Big = struct {
    data: [4096]u8,
};
```

Passing this by value may copy the whole struct.

```zig
fn process(value: Big) void {
    _ = value;
}
```

Passing a pointer avoids that copy:

```zig
fn process(value: *const Big) void {
    _ = value;
}
```

The type `*const Big` means:

```text
pointer to a Big value that this function will not modify
```

This is a common pattern:

```zig
fn readLargeThing(value: *const Big) void {
    // inspect value, but do not modify it
}

fn modifyLargeThing(value: *Big) void {
    // modify value
}
```

Use `*const T` when the function only needs to read.

Use `*T` when the function needs to modify.

#### Returning Pointers

A function can return a pointer, but you must be careful.

This is wrong:

```zig
fn bad() *i32 {
    var x: i32 = 10;
    return &x;
}
```

The variable `x` lives only while `bad` is running. When `bad` returns, `x` is gone. Returning `&x` would return a pointer to invalid memory.

That is a dangling pointer.

A better pattern is to return a pointer to memory that outlives the function call.

For example, the caller can provide the storage:

```zig
fn chooseFirst(a: *i32, b: *i32) *i32 {
    _ = b;
    return a;
}

pub fn main() void {
    var x: i32 = 10;
    var y: i32 = 20;

    const p = chooseFirst(&x, &y);
    p.* = 99;
}
```

Here, `x` and `y` live in `main`. The returned pointer points to `x`, which is still valid after `chooseFirst` returns.

The key rule:

Do not return a pointer to a local variable that dies when the function returns.

#### Optional Pointers

Sometimes a pointer may or may not exist.

In Zig, this is represented with an optional pointer:

```zig
?*T
```

Example:

```zig
fn findNumber(found: bool, value: *i32) ?*i32 {
    if (found) {
        return value;
    } else {
        return null;
    }
}
```

The return type:

```zig
?*i32
```

means:

```text
either a pointer to i32, or null
```

You must check before using it:

```zig
const std = @import("std");

fn findNumber(found: bool, value: *i32) ?*i32 {
    if (found) return value;
    return null;
}

pub fn main() void {
    var x: i32 = 42;

    const result = findNumber(true, &x);

    if (result) |p| {
        std.debug.print("found: {}\n", .{p.*});
    } else {
        std.debug.print("not found\n", .{});
    }
}
```

Inside:

```zig
if (result) |p| {
```

Zig unwraps the optional pointer. Inside that block, `p` is a normal `*i32`.

#### Single Item Pointer vs Slice

A single item pointer points to one value.

```zig
*i32
```

A slice points to a sequence of values and stores a length.

```zig
[]i32
```

Example:

```zig
var x: i32 = 10;
const p: *i32 = &x;
```

`p` points to one integer.

Example:

```zig
var data = [_]i32{ 1, 2, 3 };
const s: []i32 = data[0..];
```

`s` refers to several integers.

Do not confuse these two.

A single item pointer does not know how many items come after it. It is only for one value.

A slice knows its length, so it is usually better for arrays and buffers.

#### Pointer Syntax Summary

| Syntax | Meaning |
|---|---|
| `&x` | address of `x` |
| `*T` | pointer to mutable `T` |
| `*const T` | pointer to immutable `T` |
| `p.*` | value pointed to by `p` |
| `?*T` | optional pointer to `T` |
| `null` | no pointer value |

These forms appear constantly in Zig code.

#### A Complete Example

This program shows single item pointers in a practical way:

```zig
const std = @import("std");

const Counter = struct {
    value: i32,
};

fn reset(counter: *Counter) void {
    counter.value = 0;
}

fn printCounter(counter: *const Counter) void {
    std.debug.print("counter = {}\n", .{counter.value});
}

fn add(counter: *Counter, amount: i32) void {
    counter.value += amount;
}

pub fn main() void {
    var counter = Counter{ .value = 10 };

    printCounter(&counter);

    add(&counter, 5);
    printCounter(&counter);

    reset(&counter);
    printCounter(&counter);
}
```

Output:

```text
counter = 10
counter = 15
counter = 0
```

Notice the function signatures:

```zig
fn reset(counter: *Counter) void
```

This function modifies the counter.

```zig
fn printCounter(counter: *const Counter) void
```

This function only reads the counter.

The pointer type documents the function’s intent.

#### The Main Idea

A single item pointer is a typed address to one value.

Use `&x` to get the address of `x`.

Use `p.*` to read or write the value behind the pointer.

Use `*const T` when the function should only read.

Use `*T` when the function may modify.

A pointer is powerful because it lets code work with the original value instead of a copy. That power comes with responsibility: the pointed-to memory must still be valid when the pointer is used.

