ポインタ(*T / &変数)
『Zig』では、ポインタを使って変数のメモリアドレスを参照し、そのアドレスを経由して値を読み書きできます。ポインタ型は *T(T は指す先の型)で表し、&変数 でアドレスを取得し、ポインタ.* で間接参照(デリファレンス)します。C言語に似た仕組みですが、Zig のポインタはヌルを許容しない安全な設計になっています。
構文
// -----------------------------------------------
// *T — ポインタ型の宣言と取得
// -----------------------------------------------
var 変数: T = 値;
const ptr: *T = &変数; // & でアドレスを取得してポインタを得ます
// -----------------------------------------------
// ポインタの間接参照(デリファレンス)
// -----------------------------------------------
const 値 = ptr.*; // ptr.* で指す先の値を読み取ります
ptr.* = 新しい値; // ptr.* に代入すると指す先の値を書き換えます
// ※ const ポインタ(*const T)は書き換え不可です
// -----------------------------------------------
// *const T — 読み取り専用ポインタ
// -----------------------------------------------
const 変数: T = 値;
const ptr: *const T = &変数; // const 変数へのポインタは *const T になります
// ptr.* = 新しい値; // コンパイルエラー:const ポインタは書き換え不可です
// -----------------------------------------------
// ポインタを引数に取る関数(参照渡し)
// -----------------------------------------------
fn 関数名(ptr: *T) void {
ptr.* = 新しい値; // 呼び出し元の変数を直接書き換えます
}
関数名(&変数); // & を付けてポインタとして渡します
構文一覧
| 構文/キーワード | 概要 |
|---|---|
*T | 型 T を指す(書き換え可能な)ポインタ型です。 |
*const T | 型 T を指す読み取り専用ポインタ型です。指す先の値を変更できません。 |
&変数 | 変数のアドレスを取得してポインタを生成します。 |
ptr.* | ポインタを間接参照(デリファレンス)して指す先の値を取得します。 |
ptr.* = 値 | ポインタが指す先の値を書き換えます。*const T では使用できません。 |
fn f(ptr: *T) void | ポインタを引数に受け取る関数です。呼び出し元の変数を書き換えられます。 |
f(&変数) | & を付けて変数のアドレスを関数に渡します(参照渡しに相当します)。 |
サンプルコード
evangelion_pointer.zig
// evangelion_pointer.zig — ポインタ *T の基本サンプルです
// エヴァンゲリオンのキャラクターを使って
// アドレスの取得・間接参照・参照渡しを確認します
// 標準ライブラリをインポートします
const std = @import("std");
// -----------------------------------------------
// sync_rate を受け取るポインタ引数で同期率を更新する関数です
// *u32 を受け取ることで呼び出し元の変数を直接書き換えられます
// -----------------------------------------------
fn updateSyncRate(rate: *u32, new_rate: u32) void {
rate.* = new_rate; // デリファレンスして値を書き換えます
}
pub fn main() !void {
// 標準出力への Writer を取得します
const stdout = std.io.getStdOut().writer();
// -----------------------------------------------
// 基本:ポインタの取得とデリファレンス
// -----------------------------------------------
// 碇シンジの初期同期率を var で宣言します(ポインタで書き換えるため var が必要です)
var shinji_sync: u32 = 41;
// & で shinji_sync のアドレスを取得して *u32 型のポインタを得ます
const shinji_ptr: *u32 = &shinji_sync;
try stdout.print("=== 初号機 パイロット: 碇シンジ ===\n", .{});
// {d} で整数を表示します
try stdout.print("同期率(変数): {d}%\n", .{shinji_sync});
// ptr.* でポインタの指す先の値を読み取ります
try stdout.print("同期率(ポインタ経由): {d}%\n", .{shinji_ptr.*});
// ポインタ経由で値を書き換えます
shinji_ptr.* = 400;
try stdout.print("限界突破後の同期率: {d}%\n", .{shinji_sync});
// -----------------------------------------------
// *const T — 読み取り専用ポインタ
// -----------------------------------------------
// 綾波レイのパイロット番号は変更しないので const で宣言します
const rei_pilot_no: u32 = 0;
// const 変数へのポインタは *const u32 型になります
const rei_ptr: *const u32 = &rei_pilot_no;
try stdout.print("\n=== 零号機 パイロット: 綾波レイ ===\n", .{});
try stdout.print("パイロット番号(読み取り専用): {d}\n", .{rei_ptr.*});
// rei_ptr.* = 1; // コンパイルエラー:*const T は書き換え不可です
// -----------------------------------------------
// 関数へのポインタ渡し(参照渡し)
// -----------------------------------------------
// 惣流・アスカ・ラングレーの同期率を初期化します
var asuka_sync: u32 = 50;
try stdout.print("\n=== 弐号機 パイロット: 惣流・アスカ・ラングレー ===\n", .{});
try stdout.print("訓練時の同期率: {d}%\n", .{asuka_sync});
// & でアドレスを渡すと、関数内でポインタ経由の書き換えが呼び出し元に反映されます
updateSyncRate(&asuka_sync, 98);
try stdout.print("本番戦闘後の同期率: {d}%\n", .{asuka_sync});
updateSyncRate(&asuka_sync, 400);
try stdout.print("ベルセルク発動後の同期率: {d}%\n", .{asuka_sync});
// -----------------------------------------------
// 複数変数へのポインタ操作
// -----------------------------------------------
var kaworu_sync: u32 = 99;
var misato_level: u32 = 3; // 渚カヲルの相対評価レベル(ミサト判定)
// 異なる変数へのポインタをそれぞれ取得します
const kaworu_ptr: *u32 = &kaworu_sync;
const misato_ptr: *u32 = &misato_level;
try stdout.print("\n=== 渚カヲル / 葛城ミサト 評価 ===\n", .{});
try stdout.print("渚カヲル 同期率: {d}%\n", .{kaworu_ptr.*});
try stdout.print("葛城ミサト 警戒レベル: {d}\n", .{misato_ptr.*});
// ポインタ経由で2つの変数を同時に更新します
kaworu_ptr.* = 100;
misato_ptr.* = 5;
try stdout.print("更新後 — 渚カヲル 同期率: {d}%\n", .{kaworu_sync});
try stdout.print("更新後 — 葛城ミサト 警戒レベル: {d}\n", .{misato_level});
}
zig run evangelion_pointer.zig === 初号機 パイロット: 碇シンジ === 同期率(変数): 41% 同期率(ポインタ経由): 41% 限界突破後の同期率: 400% === 零号機 パイロット: 綾波レイ === パイロット番号(読み取り専用): 0 === 弐号機 パイロット: 惣流・アスカ・ラングレー === 訓練時の同期率: 50% 本番戦闘後の同期率: 98% ベルセルク発動後の同期率: 400% === 渚カヲル / 葛城ミサト 評価 === 渚カヲル 同期率: 99% 葛城ミサト 警戒レベル: 3 更新後 — 渚カヲル 同期率: 100% 更新後 — 葛城ミサト 警戒レベル: 5
概要
『Zig』のポインタ型 *T は、型 T の値が格納されたメモリアドレスを保持します。&変数 でその変数のアドレスを取得してポインタを生成し、ポインタ.* でアドレスが指す先の値を読み書きします。C言語の *ptr に相当する操作です。書き換え不要な場合は *const T(読み取り専用ポインタ)を使うと、誤った書き換えをコンパイル時に防げます。関数の引数に *T を受け取ると参照渡しと同じ効果になり、呼び出し元の変数を関数内から直接変更できます。なお Zig のポインタはデフォルトでヌルを許容しません。ヌルを扱う場合はオプショナルポインタ(?*T)を使います。オプショナル型の詳細については オプショナル型 ?T を、スライス(複数要素を指すポインタ)については スライス を合わせて確認してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。