---
title: "Return Local Pointer — Como Resolver em Zig"
url: "https://ziglang.com.br/erros/return-local-pointer-como-resolver-em-zig/"
markdown_url: "https://ziglang.com.br/erros/return-local-pointer-como-resolver-em-zig.MD"
description: "Entenda o erro de retornar ponteiro para variável local em Zig. Veja por que a stack é invalidada e como retornar dados corretamente."
date: "2026-02-21"
author: "Zig Brasil"
---

# Return Local Pointer — Como Resolver em Zig

Entenda o erro de retornar ponteiro para variável local em Zig. Veja por que a stack é invalidada e como retornar dados corretamente.


# Return Local Pointer — Como Resolver em Zig

## O Que Este Erro Significa

O erro de retornar ponteiro para variável local ocorre quando uma função tenta retornar um ponteiro ou slice que referencia dados na stack da função. Quando a função retorna, sua stack frame é destruída e a memória é reutilizada. O ponteiro retornado se torna um "dangling pointer" — aponta para memória inválida que será sobrescrita pela próxima chamada de função.

Zig detecta este erro em tempo de compilação na maioria dos casos:

```
error: pointer to local variable 'buffer' returned from function
```

Ou:

```
error: function returns address of local variable
```

Este é um erro clássico em linguagens com gerenciamento manual de memória (C, C++), e Zig o previne staticamente quando possível.

## Causas Comuns

### 1. Retornar Ponteiro para Array Local

```zig
fn criarBuffer() *[100]u8 {
    var buffer: [100]u8 = undefined;
    @memset(&buffer, 0);
    return &buffer; // ERRO: buffer está na stack e será destruído
}
```

### 2. Retornar Slice de Array Local

```zig
fn obterDados() []u8 {
    var dados: [50]u8 = undefined;
    @memset(&dados, 'A');
    return &dados; // ERRO: dados está na stack
}
```

### 3. Retornar Ponteiro para Struct Local

```zig
const Config = struct {
    porta: u16,
    host: []const u8,
};

fn criarConfig() *Config {
    var config = Config{
        .porta = 8080,
        .host = "localhost",
    };
    return &config; // ERRO: config está na stack
}
```

### 4. Retornar Ponteiro para Variável de Loop

```zig
fn encontrar(arr: []const u32, alvo: u32) ?*const u32 {
    for (arr) |item| {
        if (item == alvo) {
            return &item; // ERRO: item é cópia na stack
        }
    }
    return null;
}
```

### 5. Retornar String Formatada em Buffer Local

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

fn formatarNumero(n: u32) []const u8 {
    var buf: [20]u8 = undefined;
    const resultado = std.fmt.bufPrint(&buf, "{d}", .{n}) catch return "";
    return resultado; // ERRO: buf está na stack
}
```

## Como Corrigir

### Solucao 1: Retornar por Valor (Cópia)

A solução mais simples — retorne a struct ou array por valor, não por ponteiro:

```zig
const Config = struct {
    porta: u16,
    host: []const u8,
};

fn criarConfig() Config {
    return .{
        .porta = 8080,
        .host = "localhost",
    };
}

pub fn main() void {
    const config = criarConfig(); // Cópia na stack de main
    _ = config;
}
```

### Solucao 2: Alocar no Heap

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

fn criarBuffer(allocator: std.mem.Allocator) ![]u8 {
    const buffer = try allocator.alloc(u8, 100);
    @memset(buffer, 0);
    return buffer; // OK: memória está no heap
}

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

    const buf = try criarBuffer(allocator);
    defer allocator.free(buf);

    buf[0] = 42;
}
```

### Solucao 3: Receber Buffer como Parâmetro

Padrão idiomático em Zig — quem chama fornece o buffer:

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

fn formatarNumero(n: u32, buf: []u8) ![]u8 {
    return std.fmt.bufPrint(buf, "{d}", .{n});
}

pub fn main() !void {
    var buf: [20]u8 = undefined;
    const resultado = try formatarNumero(42, &buf);
    std.debug.print("Formatado: {s}\n", .{resultado});
    // buf está na stack de main — válido durante todo o escopo
}
```

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

```zig
fn encontrar(arr: []const u32, alvo: u32) ?*const u32 {
    for (arr, 0..) |item, i| {
        if (item == alvo) {
            return &arr[i]; // OK: aponta para o array original, não para cópia
        }
    }
    return null;
}

pub fn main() void {
    const dados = [_]u32{ 10, 20, 30 };
    if (encontrar(&dados, 20)) |ptr| {
        _ = ptr.*;
    }
}
```

### Solucao 5: Retornar String Literal (Comptime)

Strings literais são alocadas no segmento de dados do programa, não na stack:

```zig
fn obterMensagem(codigo: u32) []const u8 {
    return switch (codigo) {
        0 => "Sucesso",            // OK: string literal está no binário
        1 => "Erro de entrada",    // OK
        2 => "Erro de conexão",    // OK
        else => "Erro desconhecido", // OK
    };
}

pub fn main() void {
    const msg = obterMensagem(1);
    _ = msg; // Válido — string literal vive para sempre
}
```

### Solucao 6: Usar allocator.create para Structs no Heap

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

const Config = struct {
    porta: u16,
    host: []const u8,
};

fn criarConfig(allocator: std.mem.Allocator) !*Config {
    const config = try allocator.create(Config);
    config.* = .{
        .porta = 8080,
        .host = "localhost",
    };
    return config; // OK: no heap
}

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

    const config = try criarConfig(allocator);
    defer allocator.destroy(config);

    std.debug.print("Porta: {}\n", .{config.porta});
}
```

## Quando É Seguro Retornar Ponteiro

```zig
// SEGURO: ponteiro para parâmetro (vida útil >= chamador)
fn primeiro(slice: []u32) *u32 {
    return &slice[0]; // OK: slice existe no chamador
}

// SEGURO: ponteiro para global
var global: u32 = 0;
fn obterGlobal() *u32 {
    return &global; // OK: variável global vive para sempre
}

// SEGURO: ponteiro para memória alocada no heap
fn alocar(allocator: std.mem.Allocator) !*u32 {
    const ptr = try allocator.create(u32);
    ptr.* = 42;
    return ptr; // OK: heap outlives a função
}
```

## Padrões Idiomáticos em Zig

| Situação | Solução Recomendada |
|----------|-------------------|
| Retornar struct pequena | Retornar por valor |
| Retornar string formatada | Receber buffer como parâmetro |
| Retornar dados grandes | Alocar no heap (receber allocator) |
| Retornar texto fixo | Usar string literal |
| Retornar elemento de coleção | Retornar ponteiro para o original |

## Comparação com C

```c
// C — PERIGO: compila sem aviso, mas é bug
char* criar_mensagem() {
    char buf[100];
    sprintf(buf, "Olá");
    return buf; // Dangling pointer! Nenhum aviso.
}
```

```zig
// Zig — SEGURO: erro de compilação
fn criarMensagem() []u8 {
    var buf: [100]u8 = undefined;
    return &buf; // ERRO DE COMPILAÇÃO: ponteiro para local
}
```

Zig previne este bug antes de executar o programa.

## Erros Relacionados

- [Use after free](/erros/erro-use-after-free/) — Usar memória após liberação
- [Capturar ponteiro em for](/erros/erro-capturar-ponteiro-for/) — Ponteiro para variável de iteração
- [Segmentation fault](/erros/erro-segmentation-fault/) — Acesso a memória inválida
- [Stack overflow](/erros/erro-stack-overflow/) — Estouro da pilha

## Links Úteis

- [Documentação oficial do Zig — Pointers](https://ziglang.org/documentation/master/#Pointers)
- [Documentação oficial do Zig — Lifetime](https://ziglang.org/documentation/master/#Lifetime)
- [Receitas de gerenciamento de memória](/receitas/)
- [Tutorial sobre ponteiros e slices](/tutoriais/)
