Compreender a memória, manipular endereços e gerir recursos em tempo de execução com malloc, calloc, realloc e free.
Objectivos
Ao final desta aula, o estudante deverá ser capaz de:
malloc, calloc, realloc e free.
Estrutura
&)*)
Conceito
Toda variável em C é armazenada numa posição específica da memória RAM. O número que identifica essa posição é o endereço.
Armazena um valor (ex.: um número, um caractere).
int idade = 25;
// idade contém o valor 25
Armazena um endereço de memória onde está o valor de outra variável.
int *ptr = &idade;
// ptr contém o endereço de idade
Sintaxe
Para declarar um ponteiro, usamos o operador asterisco (*) logo antes do nome, indicando o tipo de dado para o qual ele vai apontar.
tipo *nomeDoPonteiro;
// Exemplo:
int *ptrInt; // Aponta para um inteiro
float *ptrFloat; // Aponta para um float
char *ptrChar; // Aponta para um caractere
int* não pode apontar directamente para um float sem cast.
Manipulação
&)Retorna o endereço de memória de uma variável.
int x = 10;
int *p = &x;
// p = endereço de x
*)Acessa ou modifica o valor armazenado no endereço apontado.
int x = 10;
int *p = &x;
*p = 20;
// x agora vale 20
& pergunta "onde moras?" · * pergunta "o que tens em casa?"
Exemplo
#include <stdio.h>
int main(void) {
int valorOriginal = 42;
int *ptr;
ptr = &valorOriginal; // ptr recebe o endereço
printf("Valor: %d\n", valorOriginal); // 42
printf("Endereço: %p\n", (void *)ptr); // 0x7ff...
printf("Via ponteiro: %d\n", *ptr); // 42
*ptr = 100; // Altera o valor original!
printf("Novo valor: %d\n", valorOriginal); // 100
return 0;
}
Segurança
Um ponteiro declarado e não inicializado aponta para um endereço aleatório (lixo).
int *ptr; // PERIGO!
*ptr = 5; // Corrompe memória!
Inicialize sempre com NULL quando não aponta para nada.
int *ptr = NULL;
if (ptr != NULL) {
*ptr = 5; // Seguro
}
NULL ou não inicializado causa segmentation fault — encerramento abrupto do programa ou travamento do microcontrolador.
Memória
int v[10];malloc(10 * sizeof(int))#include <stdlib.h>
Alocação
mallocMemory Allocation — reserva um bloco contínuo de bytes na RAM e devolve um ponteiro genérico (void*) para o primeiro byte.
void* malloc(size_t tamanhoEmBytes);
#include <stdlib.h>
int *vetor = (int *) malloc(10 * sizeof(int));
if (vetor == NULL) {
printf("Erro: Memória insuficiente!\n");
return 1;
}
calloc.
Alocação
callocContiguous Allocation — aloca memória para um array e inicializa tudo a zero.
void* calloc(size_t num_elementos, size_t tamanho);
// Exemplo: 5 inteiros, todos a 0
int *vetor = (int *) calloc(5, sizeof(int));
if (vetor == NULL) {
printf("Erro ao alocar!\n");
return 1;
}
Alocação
reallocReallocation — redimensiona um bloco de memória já alocado (para mais ou para menos).
void* realloc(void *ptr, size_t novo_tamanho);
int *temp = (int *) realloc(ptr, novo_tamanho * sizeof(int));
if (temp == NULL) {
// ptr AINDA é válido — liberta-o
free(ptr);
return 1;
}
ptr = temp; // Só actualiza depois de confirmar sucesso
ptr = realloc(ptr, ...) directamente. Se realloc falhar, perdes a referência ao bloco original → memory leak.
Alocação
freeDevolve o bloco de memória alocado ao sistema. Toda memória dinâmica deve ser libertada.
free(nomeDoPonteiro);
nomeDoPonteiro = NULL; // Boa prática
Esquecer o free → memória perdida até o programa terminar. Crítico em embarcados que ficam ligados meses.
Após o free, atribui NULL ao ponteiro para evitar dangling pointers.
Exemplo Integrado
Vamos usar calloc, malloc, realloc e free num programa único.
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
printf("Quantidade inicial de alunos: ");
if (scanf("%d", &n) != 1 || n <= 0) return 1;
// --- 1. CALLOC: notas inicializadas a 0 ---
int *notas = (int *) calloc(n, sizeof(int));
if (notas == NULL) {
printf("Erro: calloc falhou!\n");
return 1;
}
// --- 2. MALLOC: código da turma ---
int *codigo = (int *) malloc(sizeof(int));
if (codigo == NULL) {
free(notas);
return 1;
}
*codigo = 101;
Exemplo Integrado
// --- 3. REALLOC: aumentar turma ---
int novo_tamanho = n + 3;
int *temp = (int *) realloc(notas, novo_tamanho * sizeof(int));
if (temp == NULL) {
printf("Erro: realloc falhou!\n");
free(notas);
free(codigo);
return 1;
}
notas = temp;
// Preenche as novas posições (n .. n+2)
for (int i = n; i < novo_tamanho; i++) {
printf("Nota do aluno %d: ", i + 1);
scanf("%d", ¬as[i]);
}
// --- 4. FREE: libertar tudo ---
free(notas); notas = NULL;
free(codigo); codigo = NULL;
return 0;
}
Boas Práticas
Causa memory leaks. Crítico em sistemas embarcados ligados por longos períodos.
Usar um ponteiro já libertado. Mitigação: atribuir NULL após free.
Assumir que malloc funcionou gera segmentation fault em cenários de pouca memória.
malloc / calloc / realloc deve ter um free correspondente. E cada alocação deve ter o seu NULL check.
Debug
O especificador %p formata e exibe endereços de memória em hexadecimal.
#include <stdio.h>
int main(void) {
int numero = 42;
int *ptr = №
printf("Valor: %d\n", numero);
printf("Endereço de numero: %p\n", (void *)&numero);
printf("Valor guardado em ptr: %p\n", (void *)ptr);
printf("Endereço de ptr: %p\n", (void *)&ptr);
printf("Valor via *ptr: %d\n", *ptr);
return 0;
}
(void *) é recomendado para garantir compatibilidade com o formato esperado por %p.
Exercício Guiado
Escreve um programa que use aritmética de ponteiros para encontrar o maior elemento de um vetor.
int encontrarMaior(int *v, int tamanho).*(v + i) em vez de v[i].main: vetor estático, calcular tamanho com sizeof.
Exercício Guiado
#include <stdio.h>
int encontrarMaior(int *v, int tamanho) {
int maior = *v;
for (int i = 1; i < tamanho; i++) {
if (*(v + i) > maior) {
maior = *(v + i);
}
}
return maior;
}
int main(void) {
int numeros[] = {14, 85, 32, 9, 67, 41};
int tam = sizeof(numeros) / sizeof(numeros[0]);
printf("O maior é: %d\n", encontrarMaior(numeros, tam));
return 0;
}
Prática
Explica a principal diferença entre uma variável int e um ponteiro int*.
Declara uma variável com 50, cria um ponteiro para ela, altera o valor para 100 via ponteiro e imprime.
Aloca dinamicamente um vetor de 50 float, verifica sucesso e liberta a memória.
Implementa o exemplo do slide 14–15: calloc + malloc + realloc + free.
Cria um vetor dinâmico de N inteiros, pede ao utilizador e imprime só os pares.
Usa apenas aritmética de ponteiros para inverter um vetor de 10 inteiros.
Resumo
& obtém o endereço; * acede o valor.malloc / calloc / realloc alocam; free liberta.NULL.NULL após alocação.free.realloc, usar ponteiro temporário.
Referências
ASCENCIO, Ana F. G.; VENERUCH, Edilene A.
Fundamentos da Programação de Computadores. 3. ed. Pearson, 2014.
ALMEIDA, Rodrigo M. A.; MORAES, Carlos H. V.; SERAPHIM, Thatyana F. P.
Programação de Sistemas Embarcados. Elsevier, 2016.
Material do ISPSongo — Plano Analítico de Introdução à Programação em C.
Obrigado! Bons estudos e boa programação em C.