Ziglings 笔记 42: 引用传递 (Pass by Reference)

拿到了修改权限

在 Ziglings 的第 42 个练习中,我们终于打破了“函数参数不可变”的限制。 在此之前,如果我们想让一个函数改变某个变量的值,我们束手无策,因为 Zig 的函数参数默认是常量。

现在,通过指针,我们学会了引用传递

挑战:把一切变成 5

我们需要编写一个 makeFive 函数。

  1. 它接收一个指向 u8 的指针。
  2. 它需要把这个指针指向的内存里的值修改为 5。
  3. 我们需要用它来修改一个普通变量和一个数组中的特定元素。

解决方案

这是实现代码:

const std = @import("std");

pub fn main() void {
    var num: u8 = 1;
    var more_nums = [_]u8{ 1, 1, 1, 1 };

    // 1. 传递普通变量的地址
    // &num 的类型是 *u8
    makeFive(&num);
    std.debug.print("num: {}, ", .{num});

    // 2. 传递数组元素的地址
    // &more_nums[2] 的类型也是 *u8
    // 这展示了数组元素本质上就是内存中的普通变量
    makeFive(&more_nums[2]);

    std.debug.print("more_nums: ", .{});
    for (more_nums) |n| {
        std.debug.print("{} ", .{n});
    }
    std.debug.print("\n", .{});
}

// 函数签名:接收 *u8 (可变指针)
fn makeFive(x: *u8) void {
    // 核心操作:解引用并赋值
    // x 是地址,x.* 是地址里的值
    x.* = 5;
}

核心知识点总结

1. 什么时候用指针?

口诀很简单:

  • 如果你只想读取数据:直接传值(u8)或者传常量指针(*const u8,用于大数据结构)。
  • 如果你想修改数据:必须传可变指针(*u8)。

2. 解引用赋值

在 C 语言中,我们写 *x = 5。 在 Zig 中,我们写 x.* = 5。 这种后缀语法 .* 提醒我们:我们正在操作的是指针指向的对象,而不是指针本身。

3. 数组即内存

这个练习生动地演示了数组仅仅是一排紧挨着的变量。我们可以获取其中任何一个格子的地址,并把它当作一个独立的指针传给函数。这就是系统编程底层的魅力。


后续预告:我们已经习惯了指向单个元素的指针。但是,如果我们要处理一串数据(比如 C 语言中的字符串或缓冲区),单个指针还够用吗?下一篇我们将探讨 Zig 的多项指针 (Many-item Pointers)。