---
title: "Strings e Arrays em Zig: Guia Completo para Iniciantes"
url: "https://ziglang.com.br/tutoriais/strings-e-arrays-zig/"
markdown_url: "https://ziglang.com.br/tutoriais/strings-e-arrays-zig.MD"
description: "Aprenda tudo sobre arrays, slices e strings em Zig. Guia completo com exemplos práticos, operações comuns e melhores práticas para manipulação de texto."
date: "2026-02-10"
author: ""
---

# Strings e Arrays em Zig: Guia Completo para Iniciantes

Aprenda tudo sobre arrays, slices e strings em Zig. Guia completo com exemplos práticos, operações comuns e melhores práticas para manipulação de texto.


# Strings e Arrays em Zig: Guia Completo

Arrays e strings são conceitos fundamentais em qualquer linguagem de programação, e Zig não é diferente. No entanto, Zig aborda esses tipos de dados de uma maneira única que oferece tanto performance quanto segurança. Neste guia completo, você vai aprender tudo sobre **arrays**, **slices** e **strings** em Zig — desde os conceitos básicos até técnicas avançadas de manipulação.

## Índice

1. [Arrays em Zig](#arrays-em-zig)
2. [Slices: O Conceito Mais Importante](#slices-o-conceito-mais-importante)
3. [Strings em Zig](#strings-em-zig)
4. [Operações Comuns com Strings](#operações-comuns-com-strings)
5. [ArrayList: Arrays Dinâmicos](#arraylist-arrays-dinâmicos)
6. [Interoperabilidade com C](#interoperabilidade-com-c)
7. [Melhores Práticas](#melhores-práticas)
8. [Armadilhas Comuns](#armadilhas-comuns)
9. [FAQ](#faq)
10. [Próximos Passos](#próximos-passos)

---

## Arrays em Zig

Arrays em Zig são coleções de elementos do **mesmo tipo** com **tamanho fixo** conhecido em tempo de compilação.

### Sintaxe Básica

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

pub fn main() void {
    // Array de 5 inteiros
    const numeros = [5]i32{ 1, 2, 3, 4, 5 };
    
    // Zig pode inferir o tamanho
    const letras = [_]u8{ 'a', 'b', 'c' };
    
    // Array com valor repetido
    const zeros = [_]i32{0} ** 10; // 10 zeros
    
    std.debug.print("Primeiro número: {d}\n", .{numeros[0]});
    std.debug.print("Array de letras: {s}\n", .{letras});
    std.debug.print("Tamanho do array de zeros: {d}\n", .{zeros.len});
}
```

### Características dos Arrays

| Característica | Descrição |
|----------------|-----------|
| **Tamanho fixo** | Definido em tempo de compilação |
| **Tipo homogêneo** | Todos elementos do mesmo tipo |
| **Stack allocation** | Alocados na stack (rápido) |
| **Tamanho conhecido** | `array.len` disponível em comptime |

### Acesso e Iteração

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

pub fn main() void {
    const frutas = [_][]const u8{ "maçã", "banana", "laranja" };
    
    // Acesso por índice
    std.debug.print("Primeira fruta: {s}\n", .{frutas[0]});
    
    // Iteração com for
    for (frutas) |fruta| {
        std.debug.print("Fruta: {s}\n", .{fruta});
    }
    
    // Iteração com índice
    for (frutas, 0..) |fruta, i| {
        std.debug.print("{d}. {s}\n", .{ i + 1, fruta });
    }
}
```

### Arrays Multidimensionais

```zig
const matriz = [3][3]i32{
    .{ 1, 2, 3 },
    .{ 4, 5, 6 },
    .{ 7, 8, 9 },
};

// Acesso
const elemento = matriz[1][2]; // 6
```

---

## Slices: O Conceito Mais Importante

Se você vai aprender uma coisa sobre Zig, aprenda **slices**. Slices são a estrutura de dados mais usada e mais poderosa da linguagem.

### O Que é um Slice?

Um slice é uma **visão** de uma sequência contígua de elementos. Ele contém:
- Um **ponteiro** para o primeiro elemento
- Um **tamanho** (length)

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

pub fn main() void {
    const array = [_]i32{ 10, 20, 30, 40, 50 };
    
    // Criando um slice a partir de um array
    const slice = array[1..4]; // elementos 1, 2, 3 (índices 1 até 3)
    
    std.debug.print("Slice: {any}\n", .{slice});
    std.debug.print("Tamanho: {d}\n", .{slice.len});
    std.debug.print("Primeiro elemento: {d}\n", .{slice[0]});
}
```

### Sintaxe de Slicing

```zig
const array = [_]i32{ 0, 1, 2, 3, 4, 5 };

const slice1 = array[0..3];    // [0, 1, 2]
const slice2 = array[2..];     // [2, 3, 4, 5] (do índice 2 até o final)
const slice3 = array[..3];     // [0, 1, 2] (do início até índice 3)
const slice4 = array[0..array.len]; // slice completo
```

### Tipos de Slice

```zig
// Slice de elementos constantes (mais comum)
const slice_const: []const i32 = &[_]i32{1, 2, 3};

// Slice mutável (pode modificar elementos)
var array_mut = [_]i32{1, 2, 3};
const slice_mut: []i32 = array_mut[0..];

// Slice null-terminated (para interoperabilidade com C)
const slice_nt: [:0]const u8 = "hello";
```

### Slices e Ownership

Slices não possuem os dados — eles apenas **referenciam** dados existentes:

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

pub fn main() void {
    var dados = [_]u8{ 'a', 'b', 'c', 'd', 'e' };
    
    // slice1 e slice2 referenciam o mesmo array
    const slice1 = dados[0..3];
    const slice2 = dados[2..5];
    
    // Modificando através de um slice afeta o array original
    dados[2] = 'X';
    
    std.debug.print("slice1: {s}\n", .{slice1}); // "abX"
    std.debug.print("slice2: {s}\n", .{slice2}); // "Xde"
}
```

---

## Strings em Zig

Aqui está uma verdade importante: **Zig não tem um tipo string dedicado**. Em Zig, strings são simplesmente **slices de bytes UTF-8**.

### String Literais

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

pub fn main() void {
    // String literal: []const u8
    const mensagem = "Olá, Zig!";
    
    // Tipo real da string
    const msg_tipada: []const u8 = "Olá";
    
    // String multilinha
    const poema = \\\n        Rosas são vermelhas,
        Violetas são azuis,
        Zig é rápido,
        E isso é ótimo!
    ;
    
    std.debug.print("{s}\n", .{mensagem});
    std.debug.print("{s}\n", .{poema});
}
```

### Diferença: String Literal vs Slice

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

pub fn main() void {
    // String literal: array de tamanho fixo
    const literal = "Zig";
    // tipo: *const [3:0]u8 (array de 3 bytes + null terminator)
    
    // Convertendo para slice
    const slice: []const u8 = literal;
    
    std.debug.print("Tamanho do literal: {d}\n", .{literal.len});
    std.debug.print("Tamanho do slice: {d}\n", .{slice.len});
}
```

### Verificação de UTF-8

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

pub fn main() !void {
    const texto_valido = "Olá, mundo! 🌍";
    const texto_invalido = \x80\x81\x82; // bytes inválidos em UTF-8
    
    // Verificar se é UTF-8 válido
    const valido = std.unicode.utf8ValidateSlice(texto_valido);
    const invalido = std.unicode.utf8ValidateSlice(texto_invalido);
    
    std.debug.print("Texto válido? {s}\n", .{if (valido) "sim" else "não"});
    std.debug.print("Inválido? {s}\n", .{if (invalido) "sim" else "não"});
}
```

---

## Operações Comuns com Strings

### Concatenação

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

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    
    const parte1 = "Olá";
    const parte2 = "Mundo";
    
    // Alocar memória para a string concatenada
    const resultado = try std.mem.concat(allocator, u8, &.{ parte1, ", ", parte2, "!" });
    defer allocator.free(resultado);
    
    std.debug.print("{s}\n", .{resultado}); // "Olá, Mundo!"
}
```

### Busca e Substituição

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

pub fn main() !void {
    const texto = "A raposa marrom salta sobre o cão preguiçoso";
    
    // Encontrar substring
    const indice = std.mem.indexOf(u8, texto, "marrom");
    if (indice) |idx| {
        std.debug.print("'marrom' encontrado no índice: {d}\n", .{idx});
    }
    
    // Verificar se contém
    const contem = std.mem.containsAtLeast(u8, texto, 1, "raposa");
    std.debug.print("Contém 'raposa'? {s}\n", .{if (contem) "sim" else "não"});
    
    // Contar ocorrências
    const contagem = std.mem.count(u8, texto, "o");
    std.debug.print("Número de 'o's: {d}\n", .{contagem});
}
```

### Split (Dividir String)

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

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    
    const dados = "maçã,banana,laranja,uva";
    
    // Dividir por vírgula
    var iterador = std.mem.splitScalar(u8, dados, ',');
    
    std.debug.print("Frutas:\n");
    while (iterador.next()) |fruta| {
        std.debug.print("  - {s}\n", .{fruta});
    }
    
    // Split com múltiplos delimitadores
    const texto = "um;dois:três";
    var iter_multi = std.mem.splitAny(u8, texto, ";:");
    
    std.debug.print("\nDivisão múltipla:\n");
    while (iter_multi.next()) |parte| {
        std.debug.print("  [{s}]\n", .{parte});
    }
}
```

### Trim (Remover Espaços)

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

pub fn main() void {
    const texto = "   espaços extras   ";
    
    // Remover espaços do início e fim
    const trimado = std.mem.trim(u8, texto, " ");
    std.debug.print("'{}'\n", .{trimado}); // "espaços extras"
    
    // Remover whitespace (espaço, tab, newline)
    const whitespace = "\t\n  texto  \n\t";
    const limpo = std.mem.trim(u8, whitespace, &std.ascii.whitespace);
    std.debug.print("'{}'\n", .{limpo}); // "texto"
}
```

### Comparação

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

pub fn main() void {
    const a = "Zig";
    const b = "Zig";
    const c = "Rust";
    
    // Comparação lexicográfica
    const iguais = std.mem.eql(u8, a, b);
    const diferentes = std.mem.eql(u8, a, c);
    
    std.debug.print("a == b? {s}\n", .{if (iguais) "sim" else "não"});
    std.debug.print("a == c? {s}\n", .{if (diferentes) "sim" else "não"});
    
    // Ordem lexicográfica
    const ordem = std.mem.order(u8, a, c);
    std.debug.print("ordem(a, c) = {any}\n", .{ordem}); // .lt (menor que)
}
```

### Formatação

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

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    
    const nome = "Zig";
    const versao = "0.13.0";
    
    // Formatar string
    const mensagem = try std.fmt.allocPrint(allocator, "{s} versão {s}", .{ nome, versao });
    defer allocator.free(mensagem);
    
    std.debug.print("{s}\n", .{mensagem});
    
    // Formatação com largura
    const tabela = try std.fmt.allocPrint(allocator, "| {s: <10} | {s: >10} |", .{ "Linguagem", "Performance" });
    defer allocator.free(tabela);
    
    std.debug.print("{s}\n", .{tabela});
}
```

---

## ArrayList: Arrays Dinâmicos

Quando você precisa de um array que pode crescer, use `ArrayList`.

### Uso Básico

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

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    
    // Criar ArrayList de inteiros
    var lista = std.ArrayList(i32).init(allocator);
    defer lista.deinit();
    
    // Adicionar elementos
    try lista.append(10);
    try lista.append(20);
    try lista.append(30);
    
    // Adicionar múltiplos elementos
    try lista.appendSlice(&.{ 40, 50, 60 });
    
    // Inserir em posição específica
    try lista.insert(1, 15);
    
    // Acessar elementos
    std.debug.print("Primeiro: {d}\n", .{lista.items[0]});
    std.debug.print("Tamanho: {d}\n", .{lista.items.len});
    
    // Iterar
    std.debug.print("Elementos:\n");
    for (lista.items) |item| {
        std.debug.print("  {d}\n", .{item});
    }
    
    // Remover elemento
    _ = lista.orderedRemove(2);
    
    // Limpar tudo
    lista.clearRetainingCapacity();
}
```

### ArrayList de Strings

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

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    
    // ArrayList de strings (cada string precisa de alocação própria)
    var nomes = std.ArrayList([]const u8).init(allocator);
    defer {
        // Liberar cada string individualmente
        for (nomes.items) |nome| {
            allocator.free(nome);
        }
        nomes.deinit();
    }
    
    // Adicionar strings alocadas
    const nome1 = try allocator.dupe(u8, "Alice");
    const nome2 = try allocator.dupe(u8, "Bob");
    
    try nomes.append(nome1);
    try nomes.append(nome2);
    
    for (nomes.items) |nome| {
        std.debug.print("Olá, {s}!\n", .{nome});
    }
}
```

### ArrayList como Buffer de String

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

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    
    // Usar ArrayList(u8) como StringBuilder
    var builder = std.ArrayList(u8).init(allocator);
    defer builder.deinit();
    
    // Construir string gradualmente
    try builder.appendSlice("Olá");
    try builder.append(',');
    try builder.append(' ');
    try builder.appendSlice("mundo");
    try builder.append('!');
    
    // Converter para slice
    const mensagem = builder.items;
    std.debug.print("{s}\n", .{mensagem});
    
    // Ou converter para string alocada
    const mensagem_owned = try allocator.dupe(u8, builder.items);
    defer allocator.free(mensagem_owned);
}
```

---

## Interoperabilidade com C

Zig facilita a integração com código C, incluindo strings C (null-terminated).

### Strings C (null-terminated)

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

pub fn main() void {
    // String literal C (null-terminated)
    const c_str: [:0]const u8 = "Hello";
    
    // Converter para ponteiro C
    const c_ptr: [*c]const u8 = c_str;
    
    // Converter de volta para slice
    const slice: []const u8 = std.mem.span(c_ptr);
    
    std.debug.print("Slice: {s}\n", .{slice});
    std.debug.print("Tamanho: {d}\n", .{slice.len});
}
```

### Memcpy e Memset

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

pub fn main() void {
    var origem = [_]u8{ 'a', 'b', 'c', 'd', 'e' };
    var destino: [5]u8 = undefined;
    
    // Copiar memória
    @memcpy(&destino, &origem);
    std.debug.print("Destino: {s}\n", .{destino});
    
    // Preencher com valor
    @memset(&destino, 'X');
    std.debug.print("Após memset: {s}\n", .{destino});
}
```

---

## Melhores Práticas

### 1. Use `[]const u8` para Parâmetros de Função

```zig
// ✅ Bom: aceita string literals e slices
fn imprimirMensagem(msg: []const u8) void {
    std.debug.print("{s}\n", .{msg});
}

// ❌ Ruim: só aceita arrays de tamanho específico
fn imprimirMensagemRuim(msg: *const [5]u8) void {
    std.debug.print("{s}\n", .{msg});
}
```

### 2. Documente Ownership

```zig
// `texto` é emprestado (borrowed) - não assume ownership
fn processarTexto(texto: []const u8) void {
    // apenas lê texto
}

// `texto` é owned - caller deve liberar
fn criarTexto(allocator: std.mem.Allocator) ![]u8 {
    return try allocator.dupe(u8, "novo texto");
}
```

### 3. Prefira Stack Allocation Quando Possível

```zig
// ✅ Stack allocation (rápido, automático)
var buffer: [1024]u8 = undefined;
const slice = buffer[0..100];

// ⚠️ Heap allocation (mais lento, precisa gerenciar)
var lista = std.ArrayList(u8).init(allocator);
defer lista.deinit();
```

### 4. Use `std.mem` para Operações

```zig
// ✅ Use funções da std
const iguais = std.mem.eql(u8, a, b);
const indice = std.mem.indexOf(u8, texto, "abc");
const trimado = std.mem.trim(u8, texto, " ");

// ❌ Não reimplemente manualmente
fn compararManual(a: []const u8, b: []const u8) bool {
    // ... código desnecessário
}
```

---

## Armadilhas Comuns

### 1. Slices Inválidos (Use-After-Free)

```zig
// ❌ ERRADO: slice aponta para memória liberada
fn getSlice() []const u8 {
    var buffer: [100]u8 = undefined;
    return buffer[0..10]; // buffer é liberado ao retornar!
}

// ✅ CORRETO: usar allocator para memória persistente
fn getSliceAlocada(allocator: std.mem.Allocator) ![]const u8 {
    return try allocator.dupe(u8, "texto persistente");
}
```

### 2. Buffer Overflow

```zig
// ❌ ERRADO: escrita além do buffer
var buffer: [10]u8 = undefined;
@memcpy(buffer[0..20], dados[0..20]); // overflow!

// ✅ CORRETO: verificar tamanhos
const len = @min(buffer.len, dados.len);
@memcpy(buffer[0..len], dados[0..len]);
```

### 3. Esquecer de Liberar Memória

```zig
// ❌ ERRADO: memory leak
fn processar() !void {
    const texto = try allocator.dupe(u8, "dados");
    // esqueceu: defer allocator.free(texto);
}

// ✅ CORRETO: sempre liberar
fn processar() !void {
    const texto = try allocator.dupe(u8, "dados");
    defer allocator.free(texto);
    // ... usar texto
}
```

### 4. Modificar String Literals

```zig
// ❌ ERRADO: string literals são constantes
var texto = "imutável";
texto[0] = 'I'; // ERRO DE COMPILAÇÃO!

// ✅ CORRETO: criar cópia mutável
var buffer = try allocator.dupe(u8, "mutável");
defer allocator.free(buffer);
buffer[0] = 'M'; // OK
```

---

## FAQ

### Qual a diferença entre array e slice?

Arrays têm **tamanho fixo** conhecido em tempo de compilação. Slices são **ponteiros + tamanho** que podem referenciar qualquer sequência contígua de elementos, seja de arrays, heap, ou outras fontes.

### Como converter string para inteiro?

```zig
const numero = try std.fmt.parseInt(i32, "42", 10);
```

### Como converter inteiro para string?

```zig
var buffer: [20]u8 = undefined;
const texto = try std.fmt.bufPrint(&buffer, "{d}", .{42});
```

### Strings são UTF-8 em Zig?

Sim, convenção é UTF-8, mas o tipo é apenas `[]const u8`. Você é responsável por garantir validade UTF-8.

### Como lidar com strings Unicode/avançadas?

Para processamento complexo de Unicode (grapheme clusters, normalização), use bibliotecas externas como `ziglyph`.

### ArrayList vs Array?

- **Array**: tamanho fixo, stack, mais rápido
- **ArrayList**: tamanho dinâmico, heap, flexível

---

## Próximos Passos

Agora que você domina arrays, slices e strings em Zig, recomendamos continuar com:

1. **[Gerenciamento de Memória em Zig: Guia Completo](/tutoriais/gerenciamento-de-memoria-zig/)** — Aprofunde em allocators e gerenciamento de memória
2. **[Como Criar uma CLI em Zig](/tutoriais/cli-em-zig/)** — Aplique strings e arrays em um projeto prático
3. **[Tratamento de Erros em Zig](/tutoriais/tratamento-de-erros-em-zig/)** — Aprenda a lidar com erros de parsing e alocação
4. **[Parsing JSON em Zig](/tutoriais/parsing-json-zig/)** — Manipulação avançada de strings com JSON
5. **[Structs, Enums e Unions em Zig](/tutoriais/structs-enums-unions-zig/)** — Estruturas de dados mais complexas

---

## Resumo

| Conceito | Sintaxe | Uso |
|----------|---------|-----|
| Array | `[5]i32` ou `[_]i32` | Dados fixos na stack |
| Slice | `[]i32` ou `[]const i32` | Referência a sequência |
| String | `[]const u8` | Texto UTF-8 |
| ArrayList | `std.ArrayList(T)` | Array dinâmico |
| Slicing | `array[1..5]` | Criar sub-visão |

Arrays, slices e strings são fundamentais em Zig. Dominar esses conceitos é essencial para escrever código Zig idiomático, seguro e performático. Pratique com os exemplos deste guia e consulte a documentação oficial para aprofundar ainda mais.

---

*Escrito por [Camila](/sobre/) para [ZigLang Brasil](/). Última atualização: 10 de fevereiro de 2026.*

*Achou algum erro? Tem sugestões? [Contribua no GitHub](https://github.com/seu-repo/ziglangbr)*
