Ziglings 笔记 41: 指针的双重可变性

指针的“套娃”

在 Ziglings 的第 41 个练习中,我们遇到了指针最烧脑的部分。 在上一节我们区分了 *u8*const u8。这一次,我们要在变量声明的前面再加一层 varconst

这就像是一个逻辑矩阵,我们需要搞清楚到底什么是可变的。

挑战:全能指针

我们需要定义一个指针 p,它必须具备两项能力:

  1. 换目标:一开始指向 foo,后来改成指向 bar
  2. 改数据:能够对指向的数字进行 += 1 操作。

解决方案

我们需要组合 var(允许重定向)和 *u8(允许修改数据):

const std = @import("std");

pub fn main() void {
    var foo: u8 = 5;
    var bar: u8 = 10;

    // 核心定义:
    // 1. var: 说明 p 这个变量本身是可以修改的(可以存新地址)。
    // 2. *u8: 说明 p 指向的数据是可变的(可以修改内存里的值)。
    var p: *u8 = undefined;

    // 动作 1: 指向 foo 并修改它
    p = &foo;   // 重定向
    p.* += 1;   // 修改值 (foo 变成 6)

    // 动作 2: 指向 bar 并修改它
    p = &bar;   // 重定向
    p.* += 1;   // 修改值 (bar 变成 11)

    std.debug.print("foo={}, bar={}\n", .{ foo, bar });
}

核心知识点总结

我们可以把指针看作包含两个层面的对象:

1. 指针本身 (Reference)

  • const p: 这是一个固定的指针。一旦初始化指向了 A,就不能再指向 B。
  • var p: 这是一个游动的指针。可以随时让它指向别的地方。

2. 指向的内容 (Value)

  • *const T: 这是一个只读视图。通过这个指针,你不能修改数据。
  • *T: 这是一个读写视图。通过这个指针,你可以修改数据。

四种组合速查

定义能改地址吗?(p = &y)能改值吗?(p.* += 1)
const p: *const u8❌ No❌ No
const p: *u8❌ No✅ Yes
var p: *const u8✅ Yes❌ No
var p: *u8✅ Yes✅ Yes

本题要求的就是最后一种“双重可变”的情况。


后续预告:指针不仅仅是单数的。如果我想用指针操作数组(比如 C 语言中的 ptr++),在 Zig 中该怎么做?下一篇我们将探讨指针算术与多项指针。