🚀 Capítulo 13: Alocação Dinâmica de Memória (malloc, calloc, realloc e free) em C

🎯 Objetivos da Aula

Ao final desta aula, você será capaz de:

  1. Compreender a diferença entre a memória Stack (estática) e a memória Heap (dinâmica).
  2. Requisitar blocos de memória em tempo de execução usando malloc() e calloc().
  3. Redimensionar vetores alocados na Heap utilizando a função realloc().
  4. Liberar a memória alocada dinamicamente com free() evitando vazamentos de memória (Memory Leaks).

🧠 1. Memória Stack vs Memória Heap

Em C, a memória RAM alocada para uma aplicação divide-se em duas regiões principais de gerenciamento de dados:

flowchart TD
    subgraph RAM ["Organização da Memória RAM em C"]
        Stack["Memória STACK (Estática)\n- Tamanho fixo em tempo de compilação\n- Gerenciada automaticamente pelo sistema\n- Ex.: int x; float notas[10];"]
        Heap["Memória HEAP (Dinâmica)\n- Tamanho flexível em tempo de execução\n- Gerenciada MANUALMENTE pelo programador\n- Requer malloc() e free()"]
    end

Funções da Biblioteca <stdlib.h> para Gerenciamento da Heap:

  1. malloc(tamanho_em_bytes): Aloca um bloco contíguo de bytes no Heap. Retorna o ponteiro para o primeiro byte ou NULL em caso de falha. O conteúdo inicial é lixo de memória.
  2. calloc(qtd, tamanho_unidade): Aloca memória para qtd elementos e inicializa todos os bits com zero (0).
  3. realloc(ptr, novo_tamanho): Redimensiona um bloco previamente alocado, preservando o conteúdo anterior.
  4. free(ptr): Devolve o bloco de memória apontado por ptr de volta ao Sistema Operacional.

💻 2. Prática Guiada: Vetor Dinâmico de Notas em C

Vamos escrever o programa alocacao_dinamica.c para alocar dinamicamente um vetor do tamanho exato informado pelo usuário:

#include <stdio.h>
#include <stdlib.h> // Obrigatorio para malloc, calloc, free
 
int main() {
    int qtdAlunos = 0;
    float *vetorNotas = NULL;
    
    printf("Digite a quantidade de alunos da turma: ");
    scanf("%d", &qtdAlunos);
    
    // 1. Alocacao Dinamica na Heap usando malloc
    vetorNotas = (float*) malloc(qtdAlunos * sizeof(float));
    
    // 2. Validação obrigatória da alocação
    if (vetorNotas == NULL) {
        printf(">> ERRO CRITICO: Memoria insuficiente no Heap!\n");
        return 1; // Encerra com código de erro
    }
    
    printf("\n>> Memoria alocada com sucesso no endereco: %p\n", (void*)vetorNotas);
    
    // 3. Leitura dos dados no vetor dinâmico
    for (int i = 0; i < qtdAlunos; i++) {
        printf("Digite a nota do Aluno %d: ", i + 1);
        scanf("%f", &vetorNotas[i]);
    }
    
    // 4. Processamento da média
    float soma = 0.0f;
    for (int i = 0; i < qtdAlunos; i++) {
        soma += vetorNotas[i];
    }
    float mediaTurma = soma / qtdAlunos;
    
    printf("\n=========================================\n");
    printf(" Media da Turma (%d alunos): %.2f\n", qtdAlunos, mediaTurma);
    printf("=========================================\n");
    
    // 5. LIBERAÇÃO OBRIGATÓRIA DA MEMÓRIA ALOCADA!
    free(vetorNotas);
    vetorNotas = NULL; // Evita ponteiro solto (Dangling Pointer)
    printf(">> Memoria liberada com sucesso.\n");
    
    return 0;
}

⚔️ 3. Desafios Práticos (Exercícios 30/50/20)

🥉 Nível Bronze (Fixação)

  1. O que é um vazamento de memória (Memory Leak) e por que ele pode travar um servidor após longo tempo de execução?
  2. Qual a diferença de comportamento entre malloc() e calloc() ao inicializar os bytes alocados?

🥈 Nível Prata (Aplicação)

  1. Escreva um programa em C que utilize malloc() para alocar dinamicamente um vetor de int de tamanho 5. Preencha com números inteiros e depois utilize realloc() para expandir o tamanho do vetor para 10 elementos sem perder os valores anteriores.

🥇 Nível Ouro (Desafio)

  1. Escreva uma função em C struct Aluno* criarAlunoDinamico(char *nome, int idade) que aloque dinamicamente uma struct Aluno no Heap, preencha seus campos e retorne o ponteiro para a main(), onde o aluno será impresso e liberado com free().

💡 Gabaritos Sanfonados de Resposta

💡 Ver Gabarito do Nível Bronze
  1. Ocorre quando a memória é alocada dinamicamente com malloc/calloc mas o programador esquece de usar free(). A memória permanece inacessível e ocupada, podendo esgotar a RAM do servidor (Out of Memory).
  2. O malloc() apenas reserva os bytes sem limpar o conteúdo (contém “lixo” de memória). O calloc() aloca e zera explicitamente todos os bytes (0).
💡 Ver Gabarito do Nível Prata & Ouro (Código C)
#include <stdio.h>
#include <stdlib.h>
 
int main() {
    int *vetor = (int*) malloc(5 * sizeof(int));
    if (vetor == NULL) return 1;
    
    for (int i = 0; i < 5; i++) vetor[i] = (i + 1) * 10;
    
    // Expandindo para 10 elementos com realloc
    vetor = (int*) realloc(vetor, 10 * sizeof(int));
    for (int i = 5; i < 10; i++) vetor[i] = (i + 1) * 10;
    
    printf("Vetor Expandido:\n");
    for (int i = 0; i < 10; i++) printf("%d ", vetor[i]);
    printf("\n");
    
    free(vetor);
    return 0;
}

📚 Referências Teóricas Oficiais

  • KERNIGHAN, Brian W.; RITCHIE, Dennis M.. A Linguagem de Programação C. 2ª Edição. Campus, 1989. Cap. 7 (Alocação Dinâmica).
  • STALLINGS, William. Arquitetura e Organização de Computadores — Gerenciamento de Memória. 10ª Edição. Pearson, 2017.

⬅️ Capítulo Anterior (Passagem por Referência) | Voltar ao Sumário | Próximo Capítulo (Manipulação de Arquivos) ➡️