---
title: "Capturar Ponteiro em For Loop — Como Resolver em Zig"
url: "https://ziglang.com.br/erros/capturar-ponteiro-em-for-loop-como-resolver-em-zig/"
markdown_url: "https://ziglang.com.br/erros/capturar-ponteiro-em-for-loop-como-resolver-em-zig.MD"
description: "Entenda o erro de capturar ponteiro inválido em for loops em Zig. Veja como iterar corretamente e evitar referências pendentes."
date: "2026-02-21"
author: "Zig Brasil"
---

# Capturar Ponteiro em For Loop — Como Resolver em Zig

Entenda o erro de capturar ponteiro inválido em for loops em Zig. Veja como iterar corretamente e evitar referências pendentes.


# Capturar Ponteiro em For Loop — Como Resolver em Zig

## O Que Este Erro Significa

Capturar um ponteiro para a variável de iteração de um `for` loop em Zig pode levar a comportamento inesperado. A variável de captura no `for` é uma cópia local que muda a cada iteração. Se você salvar um ponteiro para ela, o ponteiro fica apontando para memória que será reutilizada ou invalidada, resultando em valores incorretos ou comportamento indefinido.

Este é um erro sutil que ocorre tanto em Zig quanto em linguagens como Go e C, e é especialmente perigoso porque pode parecer funcionar em alguns casos por coincidência.

## Causas Comuns

### 1. Guardar Ponteiro para Variável de Captura

```zig
const std = @import("std");

pub fn main() void {
    const items = [_]u32{ 10, 20, 30, 40 };
    var ponteiros: [4]*const u32 = undefined;

    for (items, 0..) |item, i| {
        ponteiros[i] = &item;
        // ERRO: &item aponta para a CÓPIA local, não para o array
        // Todos os ponteiros apontam para o mesmo endereço temporário
    }

    // Todos os ponteiros mostram o ÚLTIMO valor ou lixo
    for (ponteiros) |ptr| {
        std.debug.print("{}\n", .{ptr.*});
    }
}
```

### 2. Enviar Ponteiro de Captura para Outra Função

```zig
const std = @import("std");

var referencia_salva: ?*const u32 = null;

fn guardar(ptr: *const u32) void {
    referencia_salva = ptr;
}

pub fn main() void {
    const items = [_]u32{ 1, 2, 3 };

    for (items) |item| {
        guardar(&item); // Ponteiro para cópia temporária
    }

    // referencia_salva aponta para memória inválida
    if (referencia_salva) |ptr| {
        std.debug.print("valor: {}\n", .{ptr.*}); // Lixo ou crash
    }
}
```

### 3. Closure Capturando Variável de Loop

```zig
const std = @import("std");

pub fn main() void {
    const items = [_]u32{ 10, 20, 30 };
    var callbacks: [3]*const fn () void = undefined;

    for (items, 0..) |item, i| {
        _ = item;
        // Tentativa de capturar item em closure
        callbacks[i] = struct {
            fn call() void {
                // item não é acessível aqui de forma segura
            }
        }.call;
    }
}
```

### 4. Modificar Array via Ponteiro de Captura (Valor)

```zig
pub fn main() void {
    var numeros = [_]u32{ 1, 2, 3, 4, 5 };

    for (numeros) |item| {
        _ = item;
        // item é uma CÓPIA — modificar item não altera numeros
        // NÃO pode fazer: item = item * 2;
    }
    // numeros permanece inalterado: [1, 2, 3, 4, 5]
}
```

## Como Corrigir

### Solucao 1: Usar Ponteiro para o Array Original

```zig
const std = @import("std");

pub fn main() void {
    const items = [_]u32{ 10, 20, 30, 40 };
    var ponteiros: [4]*const u32 = undefined;

    for (&items, 0..) |*item, i| {
        // ERRADO: capturar ponteiro de iteração
        // CORRETO: usar índice para apontar para o array original
        _ = item;
        ponteiros[i] = &items[i]; // Ponteiro para o array real
    }

    // Agora os ponteiros são válidos
    for (ponteiros) |ptr| {
        std.debug.print("{}\n", .{ptr.*});
    }
}
```

### Solucao 2: Usar Captura por Ponteiro (para Mutação)

```zig
const std = @import("std");

pub fn main() void {
    var numeros = [_]u32{ 1, 2, 3, 4, 5 };

    // Captura por ponteiro — modifica o array diretamente
    for (&numeros) |*ptr| {
        ptr.* *= 2;
    }

    // numeros agora é [2, 4, 6, 8, 10]
    for (numeros) |n| {
        std.debug.print("{} ", .{n});
    }
    std.debug.print("\n", .{});
}
```

### Solucao 3: Copiar o Valor, Não o Ponteiro

```zig
const std = @import("std");

pub fn main() void {
    const items = [_]u32{ 10, 20, 30 };
    var valores: [3]u32 = undefined;

    for (items, 0..) |item, i| {
        valores[i] = item; // Copia o VALOR, não o ponteiro
    }

    // valores contém cópias corretas
    for (valores) |v| {
        std.debug.print("{} ", .{v});
    }
    std.debug.print("\n", .{});
}
```

### Solucao 4: Usar Índice ao Invés de Captura

```zig
const std = @import("std");

pub fn main() void {
    var items = [_]u32{ 1, 2, 3, 4, 5 };

    // Usar índice direto para modificar
    for (0..items.len) |i| {
        items[i] *= 2;
    }

    for (items) |item| {
        std.debug.print("{} ", .{item});
    }
    std.debug.print("\n", .{});
}
```

### Solucao 5: Armazenar em Estrutura por Valor

```zig
const std = @import("std");

const Resultado = struct {
    valor: u32,
    indice: usize,
};

pub fn main() void {
    const items = [_]u32{ 100, 200, 300 };
    var resultados: [3]Resultado = undefined;

    for (items, 0..) |item, i| {
        // Armazena por VALOR, não por ponteiro
        resultados[i] = .{
            .valor = item,
            .indice = i,
        };
    }

    for (resultados) |r| {
        std.debug.print("Índice {}: {}\n", .{ r.indice, r.valor });
    }
}
```

### Solucao 6: Ponteiro para Slice de ArrayList

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var lista = std.ArrayList(u32).init(allocator);
    defer lista.deinit();

    try lista.appendSlice(&[_]u32{ 10, 20, 30 });

    // Usar slicing para obter ponteiros estáveis
    // (cuidado: append pode invalidar o slice)
    const slice = lista.items;
    for (slice) |*item| {
        item.* += 5;
    }

    for (lista.items) |item| {
        std.debug.print("{} ", .{item});
    }
    std.debug.print("\n", .{});
}
```

## Captura por Valor vs Captura por Ponteiro

```zig
var arr = [_]u32{ 1, 2, 3 };

// Captura por VALOR — item é uma cópia (read-only)
for (arr) |item| {
    _ = item; // Cópia — modificar não afeta arr
}

// Captura por PONTEIRO — ptr aponta para o elemento real
for (&arr) |*ptr| {
    ptr.* += 1; // Modifica arr diretamente
}
```

## Regra de Ouro

1. **Nunca salve `&item`** de um `for` — é ponteiro para cópia temporária.
2. **Use `&array[i]`** se precisa de ponteiro persistente para um elemento.
3. **Use `|*ptr|`** (captura por ponteiro com `&array`) se quer modificar in-place.
4. **Copie valores, não ponteiros**, quando precisa guardar dados de iterações.

## Erros Relacionados

- [Use after free](/erros/erro-use-after-free/) — Usar memória após liberação
- [Return local pointer](/erros/erro-return-local-pointer/) — Retornar ponteiro para variável local
- [Segmentation fault](/erros/erro-segmentation-fault/) — Acesso a memória inválida

## Links Úteis

- [Documentação oficial do Zig — for](https://ziglang.org/documentation/master/#for)
- [Documentação oficial do Zig — Pointers](https://ziglang.org/documentation/master/#Pointers)
- [Receitas de iteração](/receitas/)
- [Tutorial sobre ponteiros em Zig](/tutoriais/)
