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
| Tipo | Descrição | Tamanho |
|---|---|---|
*T | Ponteiro para um T | 1 palavra |
*const T | Ponteiro constante para T | 1 palavra |
[*]T | Multi-ponteiro (sem tamanho) | 1 palavra |
[]T | Slice (ptr + len) | 2 palavras |
[*:S]T | Multi-ponteiro com sentinela | 1 palavra |
[:S]T | Slice com sentinela | 2 palavras |
?*T | Ponteiro optional | 1 palavra (null = 0) |
*anyopaque | Ponteiro opaco | 1 palavra |
*volatile T | Ponteiro volatile | 1 palavra |
*align(N) T | Ponteiro alinhado | 1 palavra |
Veja Também
- Tipos de Dados — Todos os tipos em Zig
- Arrays e Slices — Operações com slices
- Allocators — Alocação dinâmica de memória
- Interop com C — Ponteiros na FFI
- FAQ Memória — Perguntas sobre gerenciamento de memória
- Troubleshooting: Segfault — Debugando erros de ponteiro