# Fixed Arrays

### Fixed Arrays

An array is a group of values stored next to each other.

In Zig, a fixed array has a length known at compile time. The length is part of the type.

```zig
const numbers = [3]i32{ 10, 20, 30 };
```

This creates an array with 3 values. Each value has type `i32`.

The type of `numbers` is:

```zig
[3]i32
```

Read this as:

```text
array of 3 i32 values
```

The length is not just a detail. It belongs to the type. That means `[3]i32` and `[4]i32` are different types.

```zig
const a: [3]i32 = .{ 1, 2, 3 };
const b: [4]i32 = .{ 1, 2, 3, 4 };
```

These are not the same type.

#### Array Literals

You can write an array by giving its length and element type:

```zig
const letters = [4]u8{ 'a', 'b', 'c', 'd' };
```

Here:

```text
[4]u8
```

means an array of 4 bytes.

Each item is a `u8`. Character literals such as `'a'` are integer values. The byte value for `'a'` is stored in the array.

You can also let Zig infer the length:

```zig
const letters = [_]u8{ 'a', 'b', 'c', 'd' };
```

The underscore means: “compiler, count the items for me.”

So this:

```zig
const letters = [_]u8{ 'a', 'b', 'c', 'd' };
```

has type:

```zig
[4]u8
```

For beginners, this is usually the best style when the array literal itself makes the length obvious.

#### Accessing Items

Array indexes start at `0`.

```zig
const numbers = [_]i32{ 10, 20, 30 };

const first = numbers[0];
const second = numbers[1];
const third = numbers[2];
```

The first item is at index `0`, not index `1`.

So for this array:

```zig
const numbers = [_]i32{ 10, 20, 30 };
```

the indexes are:

| Index | Value |
|---:|---:|
| 0 | 10 |
| 1 | 20 |
| 2 | 30 |

Index `3` would be invalid, because the array has only 3 items.

```zig
const bad = numbers[3]; // invalid
```

In safe build modes, Zig checks array access and can catch invalid indexing.

#### Changing Array Items

If an array is declared with `const`, you cannot modify it.

```zig
const numbers = [_]i32{ 10, 20, 30 };

// numbers[0] = 99; // error
```

Use `var` when the array should be mutable:

```zig
var numbers = [_]i32{ 10, 20, 30 };

numbers[0] = 99;
```

Now the array contains:

```text
99, 20, 30
```

The array length still cannot change. A fixed array always keeps the same number of items.

You may change the values, but you may not grow or shrink the array.

#### Getting the Length

Every array has a length.

```zig
const numbers = [_]i32{ 10, 20, 30 };

const len = numbers.len;
```

Here, `numbers.len` is `3`.

Because fixed array length is known at compile time, Zig can use it for checks and optimizations.

You can loop over an array using its length:

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

pub fn main() void {
    const numbers = [_]i32{ 10, 20, 30 };

    var i: usize = 0;
    while (i < numbers.len) : (i += 1) {
        std.debug.print("{}\n", .{numbers[i]});
    }
}
```

This prints:

```text
10
20
30
```

The type `usize` is commonly used for indexes and lengths. Its size depends on the target machine.

#### Looping with `for`

A `for` loop is usually simpler when you want to visit every item.

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

pub fn main() void {
    const numbers = [_]i32{ 10, 20, 30 };

    for (numbers) |n| {
        std.debug.print("{}\n", .{n});
    }
}
```

This means: for each item in `numbers`, call it `n`, then run the loop body.

You can also get the index:

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

pub fn main() void {
    const numbers = [_]i32{ 10, 20, 30 };

    for (numbers, 0..) |n, i| {
        std.debug.print("numbers[{}] = {}\n", .{ i, n });
    }
}
```

This prints:

```text
numbers[0] = 10
numbers[1] = 20
numbers[2] = 30
```

The `0..` creates a range starting from zero.

#### Arrays Are Values

In Zig, arrays are values.

That means assigning an array to another variable copies the whole array.

```zig
var a = [_]i32{ 1, 2, 3 };
var b = a;

b[0] = 99;
```

Now:

```text
a = 1, 2, 3
b = 99, 2, 3
```

Changing `b` does not change `a`, because `b` is a copy.

This is important. If the array is large, copying it can be expensive. For large data, you often pass a slice or pointer instead. We will cover slices later.

#### Passing Arrays to Functions

A function can take an array as a parameter:

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

fn printThree(numbers: [3]i32) void {
    for (numbers) |n| {
        std.debug.print("{}\n", .{n});
    }
}

pub fn main() void {
    const values = [_]i32{ 10, 20, 30 };
    printThree(values);
}
```

The function accepts exactly `[3]i32`.

This works:

```zig
printThree([_]i32{ 10, 20, 30 });
```

This does not work:

```zig
printThree([_]i32{ 10, 20, 30, 40 });
```

The second array has type `[4]i32`, but the function expects `[3]i32`.

This strictness is useful. The compiler knows exactly what size of array the function accepts.

#### Passing a Pointer to an Array

If you do not want to copy the whole array, pass a pointer:

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

fn printThree(numbers: *const [3]i32) void {
    for (numbers.*) |n| {
        std.debug.print("{}\n", .{n});
    }
}

pub fn main() void {
    const values = [_]i32{ 10, 20, 30 };
    printThree(&values);
}
```

Here:

```zig
*const [3]i32
```

means:

```text
pointer to a constant array of 3 i32 values
```

The `&values` expression gets the address of the array.

Inside the function:

```zig
numbers.*
```

means “the array that this pointer points to.”

For beginners, this syntax may look strange at first. The key idea is simple: passing a pointer avoids copying the whole array.

#### Array Repetition

Zig can create arrays by repeating a value.

```zig
const zeroes = [_]u8{0} ** 8;
```

This creates:

```text
0, 0, 0, 0, 0, 0, 0, 0
```

The type is:

```zig
[8]u8
```

This is useful for initialization.

```zig
var buffer = [_]u8{0} ** 1024;
```

This creates a fixed buffer of 1024 bytes, all set to zero.

#### Nested Arrays

Arrays can contain arrays.

```zig
const matrix = [2][3]i32{
    .{ 1, 2, 3 },
    .{ 4, 5, 6 },
};
```

The type is:

```zig
[2][3]i32
```

Read it from left to right:

```text
array of 2 arrays, each containing 3 i32 values
```

You can access items with two indexes:

```zig
const x = matrix[0][1];
```

This gets row `0`, column `1`, which is `2`.

#### Arrays and Strings

A string literal in Zig has an array-like type.

```zig
const name = "zig";
```

This is not exactly a plain `[3]u8`. String literals include a sentinel value, which is useful for C interop and some low-level operations.

For now, think of a string literal as bytes that can be viewed as text:

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

pub fn main() void {
    const name = "zig";

    for (name) |byte| {
        std.debug.print("{}\n", .{byte});
    }
}
```

This prints the byte values:

```text
122
105
103
```

Those are the UTF-8 bytes for `z`, `i`, and `g`.

We will study strings in more detail later. The important point here is that Zig treats text as bytes, and arrays are one of the basic ways to store bytes.

#### Fixed Arrays vs Slices

A fixed array owns a known number of items.

```zig
[3]i32
```

A slice points to a sequence of items and carries a runtime length.

```zig
[]i32
```

A fixed array is good when the size is known and part of the design.

A slice is better when a function should work with many possible lengths.

For example, this function accepts exactly 3 items:

```zig
fn sumThree(numbers: [3]i32) i32 {
    return numbers[0] + numbers[1] + numbers[2];
}
```

This function accepts any number of items:

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

    for (numbers) |n| {
        total += n;
    }

    return total;
}
```

You can pass an array as a slice:

```zig
const values = [_]i32{ 10, 20, 30, 40 };

const result = sum(values[0..]);
```

The expression:

```zig
values[0..]
```

creates a slice covering the whole array.

#### When to Use Fixed Arrays

Use fixed arrays when the number of elements is known and stable.

Good examples:

```text
3D vector with 3 coordinates
RGB color with 3 channels
small lookup table
temporary stack buffer
fixed protocol header
matrix with known dimensions
```

For example:

```zig
const rgb = [3]u8{ 255, 128, 0 };
```

This clearly means: exactly 3 bytes.

Use a slice when the length may vary:

```zig
fn printAll(items: []const i32) void {
    for (items) |item| {
        std.debug.print("{}\n", .{item});
    }
}
```

The slice version is more flexible.

#### Summary

A fixed array stores a known number of values.

Its type includes both the length and the element type:

```zig
[3]i32
```

The length cannot change. If the array is mutable, the values can change, but the number of items stays fixed.

Arrays are values, so assigning or passing an array can copy the whole array. For large arrays, use a pointer or slice.

Fixed arrays are one of the simplest data structures in Zig, but they teach an important Zig habit: make size, ownership, and memory layout visible in the type.

