Carregando
0xB0Lição 12 de 20

Memória dinâmica: malloc e free

Peça memória em tempo de execução quando você não sabe os tamanhos de antemão - e devolva-a quando terminar.

16 min Questionário com 5 perguntas 2 exercícios de código
Ao final desta lição, você saberá
  • Descrever a diferença entre a stack e a heap
  • Alocar e liberar memória com malloc e free
  • Evitar vazamentos, frees duplos e bugs de uso depois do free

Até aqui, todo array teve um tamanho fixado quando você escreveu o código. Programas reais muitas vezes só descobrem quantos dados existem enquanto rodam - um arquivo de tamanho desconhecido, uma quantidade de itens escolhida pelo usuário. Para isso, o C deixa você pedir memória da heap em tempo de execução.

Stack e heap

  • Stack (pilha): onde moram as variáveis locais. A alocação é automática e rápida, e a memória desaparece quando a função retorna. O tamanho dela é limitado (muitas vezes, alguns megabytes).
  • Heap: um grande reservatório que você gerencia à mão. Você pede bytes com malloc, e eles continuam seus - mesmo depois que a função retorna - até você devolvê-los com free.

malloc e free

dynamic_array.c
1#include <stdio.h>
2#include <stdlib.h>
3
4int main(void) {
5    size_t count = 5;
6    int *numbers = malloc(count * sizeof *numbers);
7    if (numbers == NULL) {
8        fprintf(stderr, "Out of memory\n");
9        return 1;
10    }
11
12    for (size_t i = 0; i < count; i++) {
13        numbers[i] = (int)(i * 10);
14    }
15    for (size_t i = 0; i < count; i++) {
16        printf("%d ", numbers[i]);
17    }
18    printf("\n");
19
20    free(numbers);
21    numbers = NULL;
22    return 0;
23}
Saída
0 10 20 30 40

O padrão para decorar:

  1. malloc(count * sizeof *pointer) pede bytes suficientes. Usar sizeof *numbers (o tamanho daquilo para o que o ponteiro aponta) continua correto mesmo se você mudar o tipo do elemento depois.
  2. Verifique se é NULL. O malloc devolve NULL quando não consegue dar a memória.
  3. Use como um array. numbers[i] funciona exatamente como antes.
  4. Faça free exatamente uma vez quando terminar e depois dê ao ponteiro o valor NULL, para que um segundo uso acidental falhe de forma ruidosa, e não silenciosa.

O malloc não limpa a memória - ela contém lixo. calloc(count, size) aloca e zera. realloc(pointer, new_size) aumenta ou diminui uma alocação (possivelmente movendo-a).

Os três bugs clássicos de memória

BugO que acontecePrevenção
Vazamento de memóriaVocê perde o último ponteiro para uma memória sem liberá-la. Ela continua alocada até o programa terminar.Todo malloc ganha um free correspondente em todo caminho de saída.
Uso depois do freeVocê lê ou escreve uma memória depois de liberá-la. Ela pode ter sido reutilizada para outra coisa.Dê aos ponteiros o valor NULL depois do free.
Free duploVocê libera a mesma memória duas vezes, corrompendo o alocador.Libere uma vez; free(NULL) é uma operação segura que não faz nada, então zerar com NULL também ajuda aqui.

Devolvendo memória de uma função

Ao contrário de um array local, a memória da heap sobrevive à função que a alocou - então uma função pode devolvê-la com segurança. A regra que vem junto: documente quem é responsável por chamar o free. Normalmente, "quem recebe libera".

make_range.c
1#include <stdio.h>
2#include <stdlib.h>
3
4// Returns 1..n in a new array. The caller must free() it.
5int *make_range(size_t n) {
6    int *range = malloc(n * sizeof *range);
7    if (range == NULL) {
8        return NULL;
9    }
10    for (size_t i = 0; i < n; i++) {
11        range[i] = (int)i + 1;
12    }
13    return range;
14}
15
16int main(void) {
17    int *numbers = make_range(4);
18    if (numbers == NULL) {
19        return 1;
20    }
21    printf("%d %d %d %d\n", numbers[0], numbers[1], numbers[2], numbers[3]);
22    free(numbers);
23    return 0;
24}
Saída
1 2 3 4

Principais conclusões

  • A memória da stack é automática e de vida curta; a memória da heap vive até você fazer free dela.

  • Aloque com malloc(count * sizeof *p), sempre verifique se é NULL e faça free exatamente uma vez, depois dando ao ponteiro o valor NULL.

  • Vazamentos, uso depois do free e free duplo são os bugs clássicos - o AddressSanitizer (-fsanitize=address) os encontra para você.

Quiz da aula

5 perguntas · aprovação com 4 acertos · até 50 XP

Ao passar, você conclui a aula e mantém sua sequência. As perguntas erradas voltarão em sessões de revisão.

Pratique: escreva código em C

Estes exercícios rodam de verdade. Escreva o programa, clique em “Executar testes” e leia o que o compilador informa: aprender a ler as mensagens do compilador é metade do aprendizado de C.

Exercício 1

Exatamente o quanto você precisa

+25 XP

Leia uma quantidade n e depois n inteiros. Guarde-os num array alocado com malloc (exatamente n elementos), imprima a soma deles e faça free do array.

Para 4 e depois 5 10 15 20, imprima 50. Se o malloc falhar, imprima Out of memory e devolva 1.

  • Quatro números
  • Números negativos
main.c
Carregando editor…

Seu código é compilado com gcc 14 (-Wall -Wextra) e executado no Compiler Explorer (godbolt.org), um serviço público gratuito.

Exercício 2

Escreva o seu próprio strdup

+25 XP

Escreva char *duplicate(const char *s), que aloca memória suficiente para uma cópia de s (lembre do terminador!), faz a cópia e a devolve. Devolva NULL se a alocação falhar. A main lê uma palavra, a duplica, troca a primeira letra da cópia por * e imprime as duas.

Para hello, imprima hello *ello.

  • hello
  • Uma letra
main.c
Carregando editor…

Seu código é compilado com gcc 14 (-Wall -Wextra) e executado no Compiler Explorer (godbolt.org), um serviço público gratuito.

Dúvidas sobre esta lição

Travou em algum ponto? Pergunte. Descobriu algo? Compartilhe. Explicar também é uma ótima forma de aprender.

Carregando publicações…