Cheatsheet: Ponteiros em Zig

Cheatsheet: Ponteiros em Zig

Zig tem um sistema de ponteiros mais preciso que C, distinguindo entre ponteiros simples, multi-ponteiros, slices e ponteiros com sentinela.

Tipos de Ponteiros

// *T — ponteiro para um único elemento
var x: i32 = 42;
const ptr: *i32 = &x;
ptr.* = 100;  // dereferenciar

// *const T — ponteiro constante (não pode modificar)
const cptr: *const i32 = &x;
const val = cptr.*;  // ok: leitura
// cptr.* = 50;  // ERRO: não pode modificar

// [*]T — ponteiro para muitos elementos (sem tamanho conhecido)
const arr = [_]i32{ 1, 2, 3, 4, 5 };
const mptr: [*]const i32 = &arr;
const elem = mptr[2];  // 3

// []T — slice (ponteiro + tamanho)
const slice: []const i32 = &arr;
const len = slice.len;    // 5
const val2 = slice[0];    // 1
_ = val;
_ = elem;
_ = len;
_ = val2;

Criar e Dereferenciar Ponteiros

var valor: i32 = 42;

// Obter ponteiro
const ptr: *i32 = &valor;

// Dereferenciar (ler)
const lido = ptr.*;  // 42

// Dereferenciar (escrever)
ptr.* = 100;  // valor agora é 100

// Ponteiro para campo de struct
const Ponto = struct { x: f64, y: f64 };
var p = Ponto{ .x = 1.0, .y = 2.0 };
const px: *f64 = &p.x;
px.* = 10.0;  // p.x agora é 10.0
_ = lido;

Ponteiros Optional

// ?*T — ponteiro que pode ser null
var x: i32 = 42;
var opt_ptr: ?*i32 = null;
opt_ptr = &x;

// Desempacotar
if (opt_ptr) |ptr| {
    std.debug.print("Valor: {}\n", .{ptr.*});
}

// orelse para valor padrão
const seguro = if (opt_ptr) |p| p.* else 0;

// Ponteiro com sentinela optional
var sent_ptr: ?[*:0]const u8 = null;
sent_ptr = "hello";
_ = seguro;

Ponteiros com Sentinela

// [*:S]T — multi-ponteiro com sentinela
const c_string: [*:0]const u8 = "Hello, World!";
// O sentinela 0 marca o fim da string

// [:S]T — slice com sentinela
const zig_string: [:0]const u8 = "Hello, World!";
const len = zig_string.len;  // 13 (sem contar o sentinela)

// Converter entre tipos
const slice: []const u8 = zig_string;  // coerção automática
const span = std.mem.span(c_string);   // [*:0] → [:0]
_ = len;
_ = slice;
_ = span;

Alinhamento de Ponteiros

// Ponteiro com alinhamento especificado
const alinhado: *align(16) i32 = @alignCast(&valor);

// Verificar alinhamento
const alignment = @alignOf(i32);  // geralmente 4
_ = alignment;

// Packed struct pode ter ponteiros com alinhamento 1
const PackedStruct = packed struct {
    a: u3,
    b: u5,
    c: u8,
};

// Ponteiros para campos de packed struct
var ps = PackedStruct{ .a = 3, .b = 15, .c = 200 };
const ptr_c: *align(1) u8 = &ps.c;
_ = ptr_c;
_ = alinhado;

Conversão entre Ponteiros

// @ptrCast — converter entre tipos de ponteiro
const bytes: *[4]u8 = @ptrCast(&valor_i32);

// @alignCast — ajustar alinhamento
const alinhado2: *align(8) i32 = @alignCast(ponteiro_generico);

// Ponteiro ↔ Inteiro
const endereco: usize = @intFromPtr(ptr);
const ptr_back: *i32 = @ptrFromInt(endereco);

// Ponteiro opaco (*anyopaque)
const opaco: *anyopaque = @ptrCast(ptr);
const original: *i32 = @ptrCast(@alignCast(opaco));
_ = bytes;
_ = alinhado2;
_ = ptr_back;
_ = original;

Slices em Detalhe

const arr = [_]i32{ 10, 20, 30, 40, 50 };

// Criar slice
const s: []const i32 = arr[1..4];  // {20, 30, 40}

// Propriedades internas
const ptr_inicio = s.ptr;  // [*]const i32 — ponteiro para primeiro elemento
const tamanho = s.len;     // usize — número de elementos

// Slicing com ranges
const inicio = arr[0..2];    // {10, 20}
const fim = arr[3..];        // {40, 50}
const tudo: []const i32 = &arr;  // array inteiro como slice

// Slice de slice
const sub = tudo[1..3];  // {20, 30}
_ = ptr_inicio;
_ = tamanho;
_ = inicio;
_ = fim;
_ = sub;

Multi-Ponteiros

// [*]T — ponteiro para sequência de elementos (tamanho desconhecido)
const arr = [_]i32{ 1, 2, 3, 4, 5 };
const mptr: [*]const i32 = &arr;

// Acesso por índice (sem bounds checking!)
const val = mptr[3];  // 4

// Converter multi-ponteiro para slice (fornecendo tamanho)
const slice = mptr[0..5];  // []const i32 de tamanho 5

// Aritmética de ponteiros
const next = mptr + 1;    // aponta para o segundo elemento
const diff = next - mptr;  // 1
_ = val;
_ = slice;
_ = diff;

Volatile e Allowzero

// Ponteiro volatile — não otimizar leituras/escritas
// Usado para hardware-mapped memory (MMIO)
const mmio: *volatile u32 = @ptrFromInt(0x4000_0000);
const reg_val = mmio.*;  // leitura não será otimizada
mmio.* = 0xFF;           // escrita não será otimizada

// Ponteiro allowzero — permite endereço 0
const zero_ptr: *allowzero i32 = @ptrFromInt(0);
_ = reg_val;
_ = zero_ptr;

Ponteiros em Structs e Funções

const Node = struct {
    valor: i32,
    proximo: ?*Node,  // ponteiro recursivo (deve ser optional)

    pub fn append(self: *Node, novo: *Node) void {
        var atual: *Node = self;
        while (atual.proximo) |prox| {
            atual = prox;
        }
        atual.proximo = novo;
    }

    pub fn toSlice(self: *const Node, buf: []i32) []i32 {
        var count: usize = 0;
        var atual: ?*const Node = self;
        while (atual) |node| : (atual = node.proximo) {
            if (count >= buf.len) break;
            buf[count] = node.valor;
            count += 1;
        }
        return buf[0..count];
    }
};

Padrões com Ponteiros

// Ponteiro para self em métodos
const Contador = struct {
    valor: i32 = 0,

    // Mutável: recebe *Self
    pub fn incrementar(self: *Contador) void {
        self.valor += 1;
    }

    // Imutável: recebe Self (cópia) ou *const Self
    pub fn obter(self: *const Contador) i32 {
        return self.valor;
    }
};

// Ponteiro de função
const Callback = *const fn (i32) void;

fn registrar(cb: Callback) void {
    cb(42);
}

// Array de ponteiros
const strs = [_][]const u8{ "hello", "world", "zig" };
for (strs) |s| {
    std.debug.print("{s}\n", .{s});
}

Tabela de Tipos de Ponteiros

TipoDescriçãoTamanho
*TPonteiro para um T1 palavra
*const TPonteiro constante para T1 palavra
[*]TMulti-ponteiro (sem tamanho)1 palavra
[]TSlice (ptr + len)2 palavras
[*:S]TMulti-ponteiro com sentinela1 palavra
[:S]TSlice com sentinela2 palavras
?*TPonteiro optional1 palavra (null = 0)
*anyopaquePonteiro opaco1 palavra
*volatile TPonteiro volatile1 palavra
*align(N) TPonteiro alinhado1 palavra

Veja Também

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.