The std.mem module contains operations on memory, slices, bytes, and basic data movement. Much of Zig programming eventually passes through std.mem.
std.mem
The std.mem module contains operations on memory, slices, bytes, and basic data movement. Much of Zig programming eventually passes through std.mem.
A simple example copies bytes from one array into another.
const std = @import("std");
pub fn main() void {
var source = [_]u8{ 1, 2, 3, 4 };
var dest = [_]u8{ 0, 0, 0, 0 };
@memcpy(dest[0..], source[0..]);
std.debug.print("{any}\n", .{dest});
}The output is:
{ 1, 2, 3, 4 }Slices are central to std.mem.
A slice is a pointer and a length:
[]u8This means: “a runtime-sized slice of writable bytes.”
A constant slice is:
[]const u8Many functions in std.mem operate on slices rather than raw pointers.
A string in Zig is usually a slice of bytes:
const message = "hello";The type is:
*const [5:0]u8but it automatically coerces to:
[]const u8when needed.
A common operation is comparing slices.
const std = @import("std");
pub fn main() void {
const a = "zig";
const b = "zig";
const equal = std.mem.eql(u8, a, b);
std.debug.print("{any}\n", .{equal});
}The output is:
truestd.mem.eql compares elements one by one.
The first argument is the element type:
u8This tells Zig how to compare the slice contents.
Searching slices is also common.
const std = @import("std");
pub fn main() void {
const text = "hello zig";
if (std.mem.indexOf(u8, text, "zig")) |index| {
std.debug.print("found at {d}\n", .{index});
}
}The output is:
found at 6indexOf returns an optional value.
If the substring exists, the index is returned.
If not, the result is null.
Many std.mem functions follow this style.
Memory initialization is another common task.
const std = @import("std");
pub fn main() void {
var buffer: [8]u8 = undefined;
@memset(buffer[0..], 0);
std.debug.print("{any}\n", .{buffer});
}The output is:
{ 0, 0, 0, 0, 0, 0, 0, 0 }undefined means the memory initially contains unspecified values.
Zig does not automatically clear memory.
This avoids hidden work and keeps costs visible.
@memset explicitly fills memory with a value.
Slices can also be split.
const std = @import("std");
pub fn main() void {
const text = "abcdef";
const left = text[0..3];
const right = text[3..];
std.debug.print("{s}\n", .{left});
std.debug.print("{s}\n", .{right});
}The output is:
abc
defSlicing does not allocate memory.
The slices point into the original data.
Many operations in Zig avoid allocation unless explicitly requested.
std.mem also provides functions for byte order conversion, alignment calculations, tokenization, and parsing support.
For example:
| Function | Purpose |
|---|---|
std.mem.eql | Compare slices |
std.mem.indexOf | Search slices |
std.mem.startsWith | Prefix check |
std.mem.endsWith | Suffix check |
std.mem.splitSequence | Split slices |
std.mem.trim | Remove bytes from edges |
std.mem.concat | Concatenate with allocation |
A tokenizer example:
const std = @import("std");
pub fn main() void {
const text = "red,green,blue";
var it = std.mem.splitSequence(u8, text, ",");
while (it.next()) |part| {
std.debug.print("{s}\n", .{part});
}
}The output is:
red
green
blueThe iterator returns slices into the original string.
No copying occurs.
This is typical Zig design: explicit allocation, direct memory access, and predictable cost.
Exercise 14-5. Compare two strings with std.mem.eql.
Exercise 14-6. Search for a substring with std.mem.indexOf.
Exercise 14-7. Write a tokenizer that splits words separated by spaces.
Exercise 14-8. Allocate an array, fill it with a value using @memset, and print the result.