# The Allocator Interface

### The Allocator Interface

An allocator is a value that knows how to allocate and free memory.

In Zig, allocator-using code normally receives an allocator as an argument:

```zig
fn readFile(allocator: std.mem.Allocator, path: []const u8) ![]u8
```

This function does not choose the allocation policy. The caller chooses it.

That makes the function more general. It can be used with a page allocator, an arena allocator, a fixed-buffer allocator, or a testing allocator.

The type is:

```zig
std.mem.Allocator
```

It is an interface-like value. Code that receives it can ask for memory without knowing the concrete allocator behind it.

The common operation is `alloc`:

```zig
const items = try allocator.alloc(i32, 10);
defer allocator.free(items);
```

This requests memory for ten `i32` values.

The result is a slice:

```zig
[]i32
```

The slice has a pointer and a length. It does not own memory by itself. Ownership is a rule of the program.

The matching operation is `free`:

```zig
allocator.free(items);
```

The same allocator that allocated the memory must free it.

This is important. Memory allocated by one allocator must not be freed by another.

A small example:

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

pub fn main() !void {
    const allocator = std.heap.page_allocator;

    const bytes = try allocator.alloc(u8, 1024);
    defer allocator.free(bytes);

    @memset(bytes, 0);

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

Allocation can fail, so `alloc` is used with `try`.

Freeing memory usually does not fail.

The allocator also supports creating one value:

```zig
const p = try allocator.create(i32);
defer allocator.destroy(p);

p.* = 42;
```

`create(T)` allocates space for one `T` and returns `*T`.

`destroy(p)` frees memory allocated by `create`.

Use `alloc` and `free` for slices.

Use `create` and `destroy` for single values.

```zig
const xs = try allocator.alloc(i32, 8);
defer allocator.free(xs);

const x = try allocator.create(i32);
defer allocator.destroy(x);
```

These pairs should not be mixed.

Do not do this:

```zig
const x = try allocator.create(i32);
defer allocator.free(x); // wrong
```

And do not do this:

```zig
const xs = try allocator.alloc(i32, 8);
defer allocator.destroy(xs); // wrong
```

The names are part of the discipline.

Allocation also appears inside standard-library containers. For example, an `ArrayList` stores elements in memory that may grow.

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

pub fn main() !void {
    var list = std.ArrayList(i32).init(std.heap.page_allocator);
    defer list.deinit();

    try list.append(10);
    try list.append(20);

    std.debug.print("{any}\n", .{list.items});
}
```

The list receives an allocator during initialization.

When the list grows, it uses that allocator.

When `deinit` runs, the list frees its internal memory.

The allocator is still visible. It is not global. It is not hidden by the language.

The allocator interface gives Zig a simple pattern:

```zig
fn work(allocator: std.mem.Allocator) !void {
    const memory = try allocator.alloc(u8, 4096);
    defer allocator.free(memory);

    // use memory
}
```

The caller controls allocation.

The callee controls use.

Ownership must be clear between them.

Exercises:

Exercise 12-1. Allocate a slice of ten `u64` values and fill it with the numbers 0 through 9.

Exercise 12-2. Allocate one `i32` with `create`, store `123` in it, print it, and destroy it.

Exercise 12-3. Write a function that takes an allocator and returns an allocated copy of the string `"zig"`.

Exercise 12-4. Modify the `ArrayList` example to append five numbers and print their sum.

