Médio C
Alocação de matriz com limpeza com goto
Enunciado
Implemente uma função que aloca uma matriz de inteiros com linhas x colunas. Use malloc para o vetor de ponteiros e para cada linha. Se qualquer alocação falhar, libere toda a memória já alocada usando goto cleanup e retorne NULL. Se tudo der certo, retorne o ponteiro para a matriz.
Requisitos
- Alocar um vetor de
linhasponteiros paraint. - Alocar cada linha com
colunasinteiros. - Em caso de falha, liberar todas as linhas já alocadas e o vetor de ponteiros.
- Usar
goto cleanuppara centralizar a limpeza.
Código inicial
#include <stdio.h>
#include <stdlib.h>
int **cria_matriz(int linhas, int colunas) {
int **mat = NULL;
// seu código aqui
return mat;
}
int main(void) {
int **m = cria_matriz(3, 4);
if (m) {
printf("Matriz criada com sucesso.\n");
// liberar matriz (exercício)
} else {
printf("Falha ao criar matriz.\n");
}
return 0;
}
Saída esperada
Matriz criada com sucesso.
Ver dica
Inicialize mat com NULL e use um contador i para saber quantas linhas foram alocadas antes da falha.
Mostrar solução
#include <stdio.h>
#include <stdlib.h>
int **cria_matriz(int linhas, int colunas) {
int **mat = NULL;
int i;
mat = malloc(linhas * sizeof(int *));
if (mat == NULL) {
perror("malloc vetor de ponteiros");
goto cleanup;
}
for (i = 0; i < linhas; i++) {
mat[i] = malloc(colunas * sizeof(int));
if (mat[i] == NULL) {
perror("malloc linha");
goto cleanup;
}
}
return mat;
cleanup:
// libera as linhas já alocadas (i é o índice da que falhou, então i-1 até 0)
for (int j = i - 1; j >= 0; j--) {
free(mat[j]);
}
free(mat);
return NULL;
}
int main(void) {
int **m = cria_matriz(3, 4);
if (m) {
printf("Matriz criada com sucesso.\n");
// liberar matriz
for (int i = 0; i < 3; i++) {
free(m[i]);
}
free(m);
} else {
printf("Falha ao criar matriz.\n");
}
return 0;
}
Passo a passo
- Declaramos
matcomoNULLeipara controlar o progresso da alocação. - Alocamos o vetor de ponteiros com
malloc. Se falhar,perroregoto cleanup. - No laço, alocamos cada linha. Se uma falhar,
perroregoto cleanup. - No rótulo
cleanup, liberamos as linhas já alocadas. Comoié o índice da linha que falhou, liberamos dei-1até0. - Liberamos o vetor de ponteiros e retornamos
NULL. - Se tudo der certo, retornamos
matantes do rótulo.
Por que funciona
O goto evita duplicar o código de limpeza em cada ponto de falha. Como i indica quantas linhas foram alocadas com sucesso, o laço de limpeza libera apenas o que existe. Isso previne vazamentos de memória e acessos inválidos.
Erros comuns
- Liberar
mat[j]paraj >= i: acessa ponteiros não inicializados, causando segmentation fault. - Esquecer de liberar
matnocleanup: vazamento do vetor de ponteiros. - Usar
gotopara pular para um rótulo que não existe ou em escopo inválido: erro de compilação.
Outra forma de resolver
Usar uma função separada libera_matriz(int **mat, int linhas) e chamá-la em cada ponto de falha. É preferível quando a limpeza é complexa ou reutilizável.
Saída esperada
Matriz criada com sucesso.