# Many-Item Pointers

### Many-Item Pointers

A many-item pointer points to the first item in a sequence.

Its type is written with `[*]`.

```zig
var items = [_]i32{ 10, 20, 30 };
const p: [*]i32 = &items;
```

The type `[*]i32` means "pointer to many `i32` values." It does not store a length. It says where the first item is, but not how many items may be used.

Items are accessed with an index.

```zig
const first = p[0];
const second = p[1];
```

This program prints the first three values.

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

pub fn main() void {
    var items = [_]i32{ 10, 20, 30 };
    const p: [*]i32 = &items;

    std.debug.print("{d} {d} {d}\n", .{ p[0], p[1], p[2] });
}
```

The output is:

```text
10 20 30
```

A many-item pointer is close to a C pointer. It may be indexed. It may be moved with pointer arithmetic. But because it has no length, it must be used carefully.

```zig
const q = p + 1;
std.debug.print("{d}\n", .{q[0]});
```

Here `q` points at the second element of the same array. `q[0]` is the same value as `p[1]`.

Many-item pointers are useful when working with C APIs, raw memory, or sentinel-terminated data. They are less common in ordinary Zig code. Most Zig code uses slices instead.

A slice has a pointer and a length.

```zig
var items = [_]i32{ 10, 20, 30 };
const s: []i32 = items[0..];
```

The slice `s` knows that it contains three elements.

```zig
std.debug.print("{d}\n", .{s.len});
```

A many-item pointer does not know this.

```zig
const p: [*]i32 = &items;
// p has no len field
```

This is the main difference.

Use a many-item pointer when the length is known by some other rule. Use a slice when the length should travel with the pointer.

A function that takes a many-item pointer must get the length separately if it needs bounds.

```zig
fn sum(ptr: [*]const i32, len: usize) i32 {
    var total: i32 = 0;
    var i: usize = 0;

    while (i < len) : (i += 1) {
        total += ptr[i];
    }

    return total;
}
```

The caller must pass both values.

```zig
const result = sum(&items, items.len);
```

This is a common C shape: pointer plus length.

In Zig, the same function is usually clearer with a slice.

```zig
fn sum(items: []const i32) i32 {
    var total: i32 = 0;

    for (items) |item| {
        total += item;
    }

    return total;
}
```

The slice version carries the length in the argument itself.

Many-item pointers may point to mutable or constant data.

```zig
const p: [*]i32 = &items;        // may write items
const q: [*]const i32 = &items;  // may only read items
```

Writing through a mutable many-item pointer changes the original storage.

```zig
p[0] = 99;
```

Reading through a constant many-item pointer is allowed.

```zig
const x = q[0];
```

Writing through it is not.

```zig
q[0] = 99; // error
```

Many-item pointers can also be sentinel-terminated.

```zig
const name: [*:0]const u8 = "zig";
```

The type `[*:0]const u8` means a many-item pointer to bytes, ending at a zero byte. This is the shape used by many C strings.

The sentinel is not a length. It is a value that marks the end. Code must scan until it finds the sentinel.

For normal Zig strings, use slices.

```zig
const name: []const u8 = "zig";
```

For C strings, sentinel pointers are often needed.

```zig
const c_name: [*:0]const u8 = "zig";
```

A many-item pointer is a low-level tool. It is powerful because it contains little information. It is dangerous for the same reason.

The rule is simple: if the number of elements matters, prefer a slice. Use a many-item pointer only when the size is known elsewhere, or when an external interface requires it.

Exercise 5-9. Write a function `first` that takes `[*]const i32` and returns the first item.

Exercise 5-10. Write a function `sumMany` that takes `[*]const i32` and a length.

Exercise 5-11. Rewrite `sumMany` to take `[]const i32`.

Exercise 5-12. Create a many-item pointer to an array and modify the second element through it.

