for Zig 0.15.2 Buy

CHAPTER 5

Memory and Strings


Here comes a particularly interesting part: how Zig uses memory. I think I mentioned earlier in the book that, when launching a program, the operating system assigns it a portion of available memory. This is necessary for all programs we run on a computer, a smartphone, or a completely different device, such as a fridge, a robot, or a camera.

Programs always need memory to run, not just to store data, but also to execute their own instructions.

Zig, like any compiled language, eventually turns the instructions we’ve written into native machine code. That code is much more compact and harder to read than what we wrote in our files.

You could say Zig is a low-level language because it's so close to the machine’s language, though actually the source code we write is quite abstract and stylized compared to the compiled result.

Anyway, we’re not too concerned right now about digging into the compiled instructions (we’ll take a closer look in a future volume of Zen of Zig), but when we compile a program, there’s a part of the data that in Zig is defined at what we call “compile time.”

This data gets embedded in the compiled program itself, ready to be loaded into the memory assigned to the program by the operating system. Knowing it at compile time ensures its type and size are known, which is crucial for the program to run correctly.

Now, you might say: “But there are languages where you don’t have to define so many types and data sizes, and everything still works fine.” That’s true. There are plenty of languages that have nothing to do with Zig or with low-level programming. Even some languages considered “low-level” don’t require this much definition.

The thing is, Zig, in particular, is very close to machine language, which is why it needs to define and lock down many things to ensure everything works correctly as much as possible.

Just to give you an example: it’s a language so well designed that you can build a web server that serves pages at lightning speed… but it’s also low-level enough that you can write drivers for a device.

Remember how, when we talked about Variables and Constants, we tried doing this?

vars.zig

const std = @import("std");

pub fn main() void {

    var n_a = 1;

    n_a = 2;

}

The compiler would say comptime_int - something like a compile-time integer has to either be a constant or marked as comptime, and it also adds a note:

“To modify this variable at runtime, it must be declared with an explicit fixed-size type.”

In other words, we need to define whether its type is u8, u16, or whatever else we need:

$ zig run vars.zig

vars.zig:4:9: error: variable of type 'comptime_int' must be const or comptime

    var n_a = 1;

        ^~~

vars:5:7: note: to modify this variable at runtime, it must be given an explicit fixed-size number type

As you know, Zig can sometimes guess (infer) the type of a variable or constant we’re going to use. Sometimes. For example, with numeric literals (numbers written directly in the code) like 1, Zig infers them as comptime_int, though even in those cases it might ask us to explicitly define the variable's size, as it does here.

Chapter summary
Where are the bytes
© 2025 - 2026 Zen of Zig