Parameters and arguments

for Zig 0.15.2 Buy

Parameters and arguments

When we talk about parameters or arguments of a function, both terms are often used as if they were synonyms. Although they are similar, there is a subtle difference:

  // fmt and args are parameters of print

  pub fn print(comptime fmt: []const u8, args: anytype) void {

  // we pass "Hello {s}.\n" and .{"Programmer"} as arguments

  print("Hello {s}.\n", .{"Programmer"});

It is very common to use both terms interchangeably, but knowing this difference can help you be more precise when writing and explaining code.

        In Zig, by default, function parameters are immutable: they cannot be modified directly. When we pass a value to a function, it is passed by copy. This means that inside the function body, we work with a copy of the original data. Parameters are “detached” from the variables or constants used at the call site.

When passing large structures, the compiler may optimize the call by using an internal reference to that data (a pointer) instead of copying the entire content. But as programmers, we cannot know whether it chose one or the other without inspecting the generated machine code.

The most important thing to remember is that the parameter we receive inside the function body is always a copy. Even if you pass a pointer, you receive a copy of that pointer. If we take the memory address of that copy, as we do below, we must be careful: it is a local address on the function stack and becomes invalid once the function returns.

inc_return_ref.zig

const std = @import("std");

const print = std.debug.print;

// increments a value and returns the memory address

// pointed to by parameter n_x

fn inc(n_x: *u8) *const *u8 {

    // we print the address contained in n_x

    print("Address arriving contained in n_x = {}\n", .{n_x});

    // we print the address of n_x

    print("Address of n_x: {}\n", .{&n_x});

    print("What n_x points to: {}\n", .{&n_x.*});

    // we modify the data pointed to by the address

    // contained in n_x

    n_x.* += 1;

    return &n_x;

}

pub fn main() void {

    // variable

    var n_a: u8 = 41;

    print("Value n_a = {}\n", .{n_a});

    // print the address of the variable

    print("Address of n_x in main {}\n", .{&n_a});

    // increment n_a

    const p_x = inc(&n_a);

    print("Get the pointer: {}\n", .{p_x});

    print("But it already shows undefined behavior, it points to {}\n",

       .{p_x.*});

    // we print the incremented n_a

    print("Value n_a = {}\n", .{n_a});

}

$ zig run inc_return_ref.zig

Value n_a = 41

Address of n_x in main u8@7ffdf073a808

Address arriving contained in n_x = u8@7ffdf073a808

Address of n_x: *u8@7ffdf073a788

What n_x points to: u8@7ffdf073a808

Get the pointer: *u8@7ffdf073a788

But it already shows undefined behavior, it points to u8@6570756365520000

Value n_a = 42

Functions and Lists
Returning multiple values
© 2025 - 2026 Zen of Zig