Quiz (Memória Dinâmica)

Teste seu entendimento sobre malloc/free, ponteiros soltos, vazamentos de memória e calloc.

Questão 1 — Fundamentos do malloc

int *p = (int *)malloc(sizeof(int) * 3);
p[0] = 10; p[1] = 20; p[2] = 30;
printf("%d\n", p[1]);
free(p);

O que isso imprime?

10
20
30
Erro de compilação
Explicação: malloc(sizeof(int)*3) aloca espaço para 3 ints no heap. p[1] é o segundo elemento → 20.

Questão 2 — Acesso depois de free

int *p = (int *)malloc(sizeof(int));
*p = 42;
free(p);
printf("%d\n", *p);

O que acontece?

42
0
Comportamento indefinido (ponteiro solto)
Erro de compilação
Explicação: Acessar memória por um ponteiro depois do free (um ponteiro solto) é comportamento indefinido.
O valor antigo pode até parecer intacto, mas isso nunca é garantido. O hábito seguro é definir p = NULL; logo depois do free.

Questão 3 — Vazamento de memória

void func(void) {
    int *p = (int *)malloc(sizeof(int) * 100);
    *p = 42;
    // esqueceu de free(p)
}

Qual é o problema aqui?

Erro de compilação
Erro em tempo de execução
Vazamento de memória (executa, mas a memória nunca é liberada)
Nada está errado
Explicação: Quando a função retorna sem chamar free, o ponteiro é perdido e a memória alocada nunca mais pode ser devolvida ao heap.
Isso é um vazamento de memória. O programa ainda roda, mas chamar essa função repetidamente acabará esgotando a memória disponível.

Questão 4 — calloc vs malloc

int *a = (int *)calloc(5, sizeof(int));
printf("%d %d %d\n", a[0], a[2], a[4]);
free(a);

O que isso imprime?

Valores lixo
0 0 0
Erro de compilação
Segmentation Fault
Explicação: Diferente do malloc, o calloc inicializa com zero a memória alocada.
Então a saída é 0 0 0. Use calloc sempre que quiser memória inicializada com zero.

Questão 5 — Double free

int *p = (int *)malloc(sizeof(int));
*p = 10;
free(p);
free(p);  // libera o mesmo ponteiro novamente

O que acontece?

Executa normalmente
Erro de compilação
Comportamento indefinido (travamento ou corrupção do heap)
O segundo free é ignorado
Explicação: Chamar free num ponteiro já liberado é comportamento indefinido (double free).
  • Na maioria das plataformas, trava o programa ou corrompe o estado interno do heap
  • Pode até virar uma vulnerabilidade de segurança (execução de código arbitrário)
Prevenção: defina o ponteiro como NULL logo depois de liberar. free(NULL) é seguro — o padrão garante que é uma operação sem efeito.

Questão 6 — sizeof em um vetor dinâmico

// Ponteiro tem 8 bytes, int tem 4 bytes
int *p = (int *)malloc(sizeof(int) * 10);
printf("%lu\n", sizeof(p));

O que isso imprime?

40 (10 ints)
10
8 (tamanho de um ponteiro)
4
Explicação: p é uma variável ponteiro, então sizeof(p) retorna o tamanho do próprio ponteiro.
  • Diferente de vetores, sizeof não consegue dizer o tamanho de uma região alocada com malloc
  • Em sistemas 64-bit, um ponteiro tipicamente tem 8 bytes
Você precisa acompanhar o tamanho alocado em uma variável própria — o malloc não devolve essa informação.

Questão 7 — Como o realloc se comporta

int *p = (int *)malloc(sizeof(int) * 3);
int *q = p;          // backup de p
p = (int *)realloc(p, sizeof(int) * 100);
// O que acontece se usarmos q agora?

Qual afirmação sobre q depois do realloc está correta?

q sempre aponta para a mesma região que p, então é seguro usar
Se a região foi movida, q fica inválido (usá-lo é comportamento indefinido)
q é atualizado automaticamente depois do realloc
q é sempre definido como NULL
Explicação: Se o realloc não conseguir estender a região existente no mesmo lugar, ele copia os dados para um novo endereço e libera o antigo.
  • Se estender no mesmo lugar, o mesmo endereço é retornado → q ainda é válido
  • Se o bloco for movido, o endereço antigo guardado em q foi liberado, então q está inválido (ponteiro solto)
  • Se ele move ou não é definido pela implementação e imprevisível
Depois de chamar realloc, você nunca deve usar o ponteiro original — apenas o novo que o realloc retornou. Além disso, se o realloc falhar ele retorna NULL sem liberar o original, então o padrão seguro é tmp = realloc(p, ...); if (tmp) p = tmp;.

Questão 8 — Falha do malloc

int *p = (int *)malloc(sizeof(int) * 1000000000);
*p = 42;  // sem verificação de NULL

O que acontece se a alocação de memória falhar?

p é automaticamente preenchido com um ponteiro válido
Erro de compilação
p se torna NULL, e *p causa um segmentation fault
0 é atribuído a *p
Explicação: Quando o malloc falha, ele retorna NULL.
  • Desreferenciar *p sem verificar se é NULL trava o programa
  • Sempre coloque depois if (p == NULL) { /* tratar erro */ }
A forma segura é:
int *p = malloc(...);
if (p == NULL) {
    fprintf(stderr, "Out of memory\n");
    return 1;
}

Questão 9 — free(NULL)

int *p = NULL;
free(p);  // libera um ponteiro NULL
printf("OK\n");

O que acontece?

Segmentation fault
Nada acontece, "OK" é impresso
Erro de compilação
Comportamento indefinido
Explicação: O padrão garante que free(NULL) é uma operação sem efeito.
  • Você pode chamar free sem verificar NULL, o que simplifica o código de tratamento de erros
  • Não é preciso uma guarda if (p != NULL) free(p);
Liberar um ponteiro já liberado (não NULL, mas inválido) ainda é comportamento indefinido. O idiom seguro é definir p = NULL; logo depois de cada free.

Resultado

Responda todas as questões para ver sua pontuação.
Início