Zig C Memory
C memory is memory requested from the C library while a program runs. The program must release that memory when it is done with it.
Requesting bytes
This program requests five bytes and fills them with letters. The block is released with defer when the function returns.
const std = @import("std");
const c = @cImport({
@cInclude("stdlib.h");
@cInclude("string.h");
});
pub fn main() !void {
const out = std.io.getStdOut().writer();
const raw = c.malloc(5) orelse return error.OutOfMemory;
defer c.free(raw);
const buf: [*]u8 = @ptrCast(raw);
buf[0] = 'Z';
buf[1] = 'i';
buf[2] = 'g';
buf[3] = '!';
buf[4] = 0;
try out.print("text: {s}\n", .{buf[0..4]});
try out.print("len: {d}\n", .{c.strlen(buf)});
}Declaring the request by hand
The request and release functions can also be declared by hand. This program requests four bytes and adds the numbers stored in them.
const std = @import("std");
extern fn malloc(size: usize) ?*anyopaque;
extern fn free(ptr: ?*anyopaque) void;
pub fn main() !void {
const out = std.io.getStdOut().writer();
const raw = malloc(4) orelse return error.OutOfMemory;
defer free(raw);
const nums: [*]u8 = @ptrCast(raw);
nums[0] = 10;
nums[1] = 20;
nums[2] = 30;
nums[3] = 40;
try out.print("sum: {d}\n", .{nums[0] + nums[1] + nums[2] + nums[3]});
}Zeroed memory
A zeroing request returns memory already filled with zeros. This program requests three bytes and prints all three.
const std = @import("std");
const c = @cImport({
@cInclude("stdlib.h");
});
pub fn main() !void {
const out = std.io.getStdOut().writer();
const raw = c.calloc(3, 1) orelse return error.OutOfMemory;
defer c.free(raw);
const zb: [*]u8 = @ptrCast(raw);
try out.print("zero: {d} {d} {d}\n", .{ zb[0], zb[1], zb[2] });
}Example
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "cmem",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
exe.linkSystemLibrary("c");
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);
b.step("run", "Run the app").dependOn(&run_cmd.step);
}Key points
- Malloc: malloc is a C function that requests a block of memory of a given size.
- Free: free is a C function that releases memory that was requested earlier.
- Null: null is the empty value returned when a request cannot be satisfied.
- Releasing with defer keeps the release paired with the request even if later code returns early.
- Calloc: calloc is a C function that requests memory already filled with zeros.
- A C block must be released exactly once, since releasing it twice is an error.
- System library: a system library is a library supplied with the operating system, such as the C library.
The build file links the C library with linkSystemLibrary. The program then requests five bytes, fills them with letters, and releases the block with defer. The printed word proves the block held the letters until the end.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
When should memory requested with malloc be released?