Alocação Dinâmica de Memória em C++

Para Alunos de Engenharia

Tipos de Memória no Computador

  • Stack (Pilha)
  • Heap (Monte)

Papel do Compilador

  • Traduz o código-fonte para linguagem de máquina
  • Aloca espaço na stack para variáveis locais
  • Gera instruções para alocação/desalocação na heap
  • Otimiza o uso de memória e execução do programa

Papel do Sistema Operacional

  • Gerencia a memória física do computador
  • Aloca memória para os processos em execução
  • Implementa memória virtual
  • Protege a memória entre diferentes processos

Stack vs Heap

Stack

  • Alocação automática
  • Rápida
  • Tamanho limitado

Heap

  • Alocação manual
  • Mais flexível
  • Maior overhead

Memória total - Stack vs Heap

Memória Total
Stack (cresce para baixo)
↕ (espaço livre) ↕
Heap (cresce para cima)

Alocação na Stack vs Heap


// Alocação na stack (automática)
int x = 5;

// Alocação na heap (manual)
int* y = new int(5);

// Não esqueça de liberar a memória alocada na heap
delete y;
y = nullptr;
                

Funções new e delete


// Aloca memória para um inteiro na heap
int* ptr = new int;  

// Atribui o valor 10 ao endereço alocado
*ptr = 10;           

// Libera a memória alocada
delete ptr;          

// Define o ponteiro como nulo após deletar (boa prática)
ptr = nullptr;       
                

Alocação de Arrays


// Define o tamanho do array
int size = 5;

// Aloca um array de 5 inteiros na heap
int* arr = new int[size];  

// Preenche o array
for(int i = 0; i < size; i++) {
    arr[i] = i * 2;  // [0, 2, 4, 6, 8]
}

// Libera a memória do array
delete[] arr;  

// Define o ponteiro como nulo após deletar
arr = nullptr;
                

Entendendo Ponteiros e Arrays

  • Um ponteiro não aponta para um array inteiro, mas para o primeiro elemento
  • A alocação é feita de forma contígua na memória
  • O programa usa aritmética de ponteiros para acessar elementos subsequentes

Ponteiros e Arrays - Exemplo


int* arr = new int[5];  // Aloca 5 inteiros contíguos
// arr aponta para o primeiro elemento

// Acesso aos elementos:
arr[0] = 10;  // Primeiro elemento
arr[1] = 20;  // Segundo elemento (*(arr + 1))
arr[2] = 30;  // Terceiro elemento (*(arr + 2))

// arr[i] é equivalente a *(arr + i)
                

A contiguidade na memória permite acesso eficiente a todos os elementos

Alocação de Matrizes


int rows = 3, cols = 4;

// Aloca um array de ponteiros (cada ponteiro representará uma linha)
int** matrix = new int*[rows];

// Para cada linha, aloca um array de inteiros (colunas)
for(int i = 0; i < rows; i++) {
    matrix[i] = new int[cols];
}

// Exemplo de uso: atribui 42 à posição [1][2]
matrix[1][2] = 42;

// Liberação da memória (processo inverso da alocação)
for(int i = 0; i < rows; i++) {
    delete[] matrix[i];  // Libera cada linha
}
delete[] matrix;  // Libera o array de ponteiros
                

Representação Visual da Matriz

int** int* int* int*
1 5 9
2 6 10
3 7 11
4 8 12

matrix é um ponteiro para um array de ponteiros.

Cada ponteiro no array aponta para um array de inteiros (uma linha da matriz).

Passagem de Matrizes para Funções


// Função que recebe uma matriz como parâmetro
void processMatrix(int** matrix, int rows, int cols) {
    // Multiplica cada elemento da matriz por 2
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < cols; j++) {
            matrix[i][j] *= 2;
        }
    }
}

// Chamada da função
processMatrix(matrix, 3, 4);
                

Conclusão

  • A alocação dinâmica permite criar estruturas de dados flexíveis
  • Entender ponteiros e alocação de memória é crucial em C++
  • Sempre libere a memória alocada manualmente para evitar vazamentos
  • A compreensão da stack vs heap ajuda na otimização de programas
  • O gerenciamento eficiente de memória é essencial para programas robustos