# Fixed-Size Arrays

### Fixed-Size Arrays

An array is a sequence of values of the same type.

A fixed-size array has its length as part of its type. This array has five `u8` values:

```zig
const a = [5]u8{ 10, 20, 30, 40, 50 };
```

The type of `a` is:

```zig
[5]u8
```

This means: an array of 5 values, each of type `u8`.

Array elements are numbered from zero.

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

pub fn main() void {
    const a = [5]u8{ 10, 20, 30, 40, 50 };

    std.debug.print("{d}\n", .{a[0]});
    std.debug.print("{d}\n", .{a[4]});
}
```

The output is:

```text
10
50
```

The expression `a[0]` selects the first element. The expression `a[4]` selects the last element. Since the array has length 5, there is no `a[5]`.

Zig checks array indexing when it can. An index known to be outside the array is an error. An index computed at run time is checked in safe builds.

An array may be mutable:

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

pub fn main() void {
    var a = [3]i32{ 1, 2, 3 };

    a[0] = 10;
    a[2] = 30;

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

The output is:

```text
10 2 30
```

The length of an array is available with `.len`:

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

pub fn main() void {
    const a = [4]i32{ 7, 8, 9, 10 };

    std.debug.print("length = {d}\n", .{a.len});
}
```

The output is:

```text
length = 4
```

The length is not stored as a separate run-time field in the ordinary sense. It is part of the array type. The compiler knows it.

A common loop over an array is:

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

pub fn main() void {
    const a = [5]i32{ 1, 2, 3, 4, 5 };

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

Here `x` is each element of the array.

To get both the index and the element, write:

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

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

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

The output is:

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

Arrays are values. Assigning an array copies the whole array.

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

pub fn main() void {
    var a = [3]i32{ 1, 2, 3 };
    var b = a;

    b[0] = 99;

    std.debug.print("a[0] = {d}\n", .{a[0]});
    std.debug.print("b[0] = {d}\n", .{b[0]});
}
```

The output is:

```text
a[0] = 1
b[0] = 99
```

Changing `b` does not change `a`. They are separate arrays.

This matters. A large array passed by value is copied. When a function should work on the original array, pass a pointer or a slice.

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

fn setFirst(a: *[3]i32) void {
    a[0] = 100;
}

pub fn main() void {
    var nums = [3]i32{ 1, 2, 3 };

    setFirst(&nums);

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

The output is:

```text
100
```

The type `*[3]i32` means a pointer to an array of three `i32` values. The expression `&nums` gives the address of the array.

Fixed-size arrays are best when the length is known at compile time and belongs to the data itself: a color with four channels, a small buffer, a machine word split into bytes, a table with a fixed number of entries.

For data whose length changes at run time, Zig usually uses slices. A slice is a pointer plus a length. Arrays and slices are closely related, but they are not the same type.

Exercises.

Exercise 6-1. Write a program that declares an array of 10 integers and prints them in order.

Exercise 6-2. Modify the program to print the elements in reverse order.

Exercise 6-3. Write a function that takes `*[5]i32` and sets every element to zero.

Exercise 6-4. Write a program that copies one array to another, changes the second array, and prints both arrays.

