Código executável completo demonstrando ciclo de vida seguro no Heap, expansão dinâmica com realloc e limpeza total para auditoria com Valgrind.


📄 Exemplo 1: Vetor Dinâmico Redimensionável (vetor_dinamico.c)

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct {
    int *dados;
    size_t tamanho;
    size_t capacidade;
} VetorDinamico;

bool inicializarVetor(VetorDinamico *v, size_t capacidadeInicial) {
    v->dados = (int*)malloc(capacidadeInicial * sizeof(int));
    if (v->dados == NULL) return false;
    v->tamanho = 0;
    v->capacidade = capacidadeInicial;
    return true;
}

bool adicionarElemento(VetorDinamico *v, int elemento) {
    if (v->tamanho == v->capacidade) {
        size_t novaCapacidade = v->capacidade * 2;
        printf(">> [HEAP]: Expandindo capacidade de %zu para %zu elementos...\n", 
               v->capacidade, novaCapacidade);

        // Padrão seguro de realocação com ponteiro temporário
        void *temp = realloc(v->dados, novaCapacidade * sizeof(int));
        if (temp == NULL) {
            fprintf(stderr, "[ERRO]: Falha de memoria ao expandir Heap!\n");
            return false;
        }
        v->dados = (int*)temp;
        v->capacidade = novaCapacidade;
    }

    v->dados[v->tamanho++] = elemento;
    return true;
}

void liberarVetor(VetorDinamico *v) {
    if (v->dados != NULL) {
        free(v->dados);
        v->dados = NULL; // Neutralização anti-dangling
    }
    v->tamanho = 0;
    v->capacidade = 0;
}

int main(void) {
    VetorDinamico v;

    printf("====================================================\n");
    printf(" 💾 VETOR DINAMICO NO HEAP COM EXPANSÃO AUTOMATICA\n");
    printf("====================================================\n");

    if (!inicializarVetor(&v, 2)) {
        fprintf(stderr, "Falha na alocacao inicial!\n");
        return EXIT_FAILURE;
    }

    for (int i = 10; i <= 60; i += 10) {
        adicionarElemento(&v, i);
    }

    printf("\nElementos no Vetor Dinamico (%zu itens):\n[ ", v.tamanho);
    for (size_t i = 0; i < v.tamanho; i++) {
        printf("%d ", v.dados[i]);
    }
    printf("]\n");

    // Limpeza total de memória (Valgrind Clean)
    liberarVetor(&v);
    printf(">> Memoria desalocada com sucesso. Valgrind Clean! ✅\n");
    printf("====================================================\n");

    return EXIT_SUCCESS;
}

📄 Exemplo 2: Alocação de Matriz Dinâmica 2D Contígua (matriz_dinamica.c)

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    size_t linhas = 3;
    size_t colunas = 4;

    // Alocação contígua em um único bloco de Heap (Alta Localidade de Cache)
    int *matriz = (int*)calloc(linhas * colunas, sizeof(int));
    if (matriz == NULL) {
        fprintf(stderr, "Falha ao alocar matriz!\n");
        return EXIT_FAILURE;
    }

    // Preenchimento utilizando a fórmula de linearização: (i * colunas + j)
    for (size_t i = 0; i < linhas; i++) {
        for (size_t j = 0; j < colunas; j++) {
            matriz[i * colunas + j] = (int)((i + 1) * 10 + (j + 1));
        }
    }

    printf("====================================================\n");
    printf(" 📐 MATRIZ DINAMICA 2D CONTIGUA NO HEAP (3x4)\n");
    printf("====================================================\n");
    for (size_t i = 0; i < linhas; i++) {
        printf("[ ");
        for (size_t j = 0; j < colunas; j++) {
            printf("%3d ", matriz[i * colunas + j]);
        }
        printf("]\n");
    }

    free(matriz);
    matriz = NULL;
    printf("====================================================\n");

    return EXIT_SUCCESS;
}