⚡ Zig Guide LiveUnofficial
✓ Zig 0.17.0-dev.1454+5faa79730On an older Zig?

Sentinel Termination

const std = @import("std");
const expect = std.testing.expect;

test "sentinel-terminated array" {
    // `[3:0]u8` is three bytes plus a guaranteed 0 at index 3.
    const array: [3:0]u8 = .{ 1, 2, 3 };
    try expect(array.len == 3); // the sentinel is not counted
    try expect(array[3] == 0); // but it is there
}

test "string literals are sentinel terminated" {
    const literal = "hi";
    try expect(@TypeOf(literal) == *const [2:0]u8);
    try expect(literal.len == 2);
    try expect(literal[2] == 0); // free C compatibility
}

test "span recovers the length from a sentinel" {
    const c_string: [*:0]const u8 = "hello";
    // `[*:0]T` has no length, but the sentinel makes it recoverable.
    const slice = std.mem.span(c_string);
    try expect(slice.len == 5);
    try expect(std.mem.eql(u8, slice, "hello"));
}

test "sentinel slices coerce to ordinary ones" {
    const sentinel_slice: [:0]const u8 = "abc";
    const plain: []const u8 = sentinel_slice;
    try expect(plain.len == 3);
}

A sentinel-terminated type guarantees a specific value sits just past the end. The syntax puts it after a colon:

TypeMeaning
[3:0]u83 bytes, plus a guaranteed 0 at index 3
[:0]u8slice with a 0 after the last element
[*:0]u8many-item pointer, terminated by 0

The sentinel is not counted in .len, but it is really there and you may read it.

String literals get this for free

const literal = "hi";   // *const [2:0]u8
literal.len;            // 2
literal[2];             // 0

So passing a Zig string literal to a C function that wants const char * needs no conversion and no copy. That is the whole point: C compatibility without paying for it in ordinary Zig code, where you still get the length.

Recovering a length

[*:0]T has no length, but the sentinel makes it discoverable:

const slice = std.mem.span(c_string);   // scans to the sentinel

This is O(n), which is exactly the cost C pays for strlen. Do it once at the boundary and work with slices from there.