Skip to content

Parameter Syntax

Function parameters are the inputs of a function.

Function Parameters

Function parameters are the inputs of a function.

They allow functions to work with different values instead of hardcoded data.

Without parameters, functions are limited:

fn printNumber() void {
    std.debug.print("{}\n", .{42});
}

This function can only print 42.

With parameters:

fn printNumber(value: i32) void {
    std.debug.print("{}\n", .{value});
}

Now the function can print any integer.

printNumber(10);
printNumber(99);
printNumber(-5);

Output:

10
99
-5

Parameters make functions reusable.

Parameter Syntax

A parameter has two parts:

name: type

Example:

value: i32
  • value is the parameter name
  • i32 is the parameter type

A function with one parameter:

fn square(x: i32) i32 {
    return x * x;
}

Here:

  • parameter name: x
  • parameter type: i32
  • return type: i32

Multiple Parameters

Functions can have multiple parameters.

fn add(a: i32, b: i32) i32 {
    return a + b;
}

Calling it:

const result = add(10, 20);

The values are passed in order:

a = 10
b = 20

Parameters are separated by commas.

fn move(x: i32, y: i32, speed: f32) void {

}

Arguments vs Parameters

These words are related but different.

TermMeaning
Parametervariable in the function definition
Argumentactual value passed during the call

Example:

fn add(a: i32, b: i32) i32 {
    return a + b;
}

Here a and b are parameters.

add(5, 8);

Here 5 and 8 are arguments.

Programmers sometimes use the words interchangeably in casual conversation, but technically they are different.

Parameters Create Local Variables

Inside the function, parameters behave like local variables.

Example:

fn double(value: i32) i32 {
    const result = value * 2;

    return result;
}

value exists only inside the function.

Outside the function, it does not exist.

pub fn main() void {
    double(10);

    // ERROR
    // value does not exist here
}

This isolation helps keep programs organized.

Type Checking

Zig checks parameter types strictly.

Example:

fn multiply(a: i32, b: i32) i32 {
    return a * b;
}

Correct:

multiply(3, 4);

Incorrect:

multiply("hello", "world");

The compiler rejects invalid types before the program runs.

This is one reason Zig programs are reliable.

Integer Parameters

Common integer parameter types:

TypeMeaning
u8unsigned 8-bit integer
u32unsigned 32-bit integer
i32signed 32-bit integer
usizesize/index integer

Example:

fn setVolume(level: u8) void {
    std.debug.print("Volume: {}\n", .{level});
}

u8 allows values from 0 to 255.

Floating Point Parameters

Floating-point types store decimal numbers.

Common types:

TypeMeaning
f3232-bit float
f6464-bit float

Example:

fn area(radius: f64) f64 {
    return 3.14159 * radius * radius;
}

Calling:

const result = area(5.0);

Boolean Parameters

Booleans store true or false.

Example:

fn setEnabled(enabled: bool) void {
    if (enabled) {
        std.debug.print("Enabled\n", .{});
    } else {
        std.debug.print("Disabled\n", .{});
    }
}

Calling:

setEnabled(true);
setEnabled(false);

Output:

Enabled
Disabled

String Parameters

Strings in Zig are usually slices of bytes.

Example:

fn greet(name: []const u8) void {
    std.debug.print("Hello, {s}!\n", .{name});
}

Calling:

greet("Alice");

Output:

Hello, Alice!

This type:

[]const u8

means:

  • [] → slice
  • const → read-only
  • u8 → bytes

You will learn slices in detail later.

For now, think of this as Zig’s standard string type.

Passing Structs

Functions can receive structs.

Example:

const Point = struct {
    x: i32,
    y: i32,
};

fn printPoint(point: Point) void {
    std.debug.print("({}, {})\n", .{
        point.x,
        point.y,
    });
}

Calling:

const p = Point{
    .x = 10,
    .y = 20,
};

printPoint(p);

Output:

(10, 20)

Functions can work with complex data, not just primitive values.

Passing Pointers

Sometimes copying data is expensive.

Instead of passing the whole value, you pass a pointer.

Example:

fn increment(value: *i32) void {
    value.* += 1;
}

Calling:

var number: i32 = 10;

increment(&number);

After the call:

number = 11

The operator:

&number

gets the address of number.

The type:

*i32

means “pointer to i32.”

Pointers are extremely important in Zig.

Parameters Are Immutable by Default

Function parameters cannot normally be reassigned.

Example:

fn test(value: i32) void {
    // ERROR
    // value = 5;
}

This prevents accidental modification.

If you need a mutable variable, create a new one:

fn test(value: i32) void {
    var local = value;

    local += 1;
}

This rule improves clarity.

Parameter Shadowing

Avoid reusing parameter names.

Bad example:

fn test(value: i32) void {
    const value = 10;
}

This creates confusion.

Use distinct names instead.

Too Many Parameters

Functions with too many parameters become hard to use.

Bad:

fn createUser(
    name: []const u8,
    age: u8,
    height: f32,
    weight: f32,
    country: []const u8,
    city: []const u8,
    active: bool,
) void {

}

This is difficult to read and easy to misuse.

Often a struct is better:

const User = struct {
    name: []const u8,
    age: u8,
    height: f32,
    weight: f32,
    country: []const u8,
    city: []const u8,
    active: bool,
};

fn createUser(user: User) void {

}

This approach scales better.

A Complete Example

const std = @import("std");

fn calculateArea(width: f64, height: f64) f64 {
    return width * height;
}

fn printArea(area: f64) void {
    std.debug.print("Area: {}\n", .{area});
}

pub fn main() void {
    const area = calculateArea(5.0, 3.0);

    printArea(area);
}

Output:

Area: 15

Notice how each function has a focused job:

  • calculateArea computes
  • printArea displays
  • main coordinates the flow

This separation is one of the core ideas of clean software design.