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 linhas ponteiros para int.
  • Alocar cada linha com colunas inteiros.
  • Em caso de falha, liberar todas as linhas já alocadas e o vetor de ponteiros.
  • Usar goto cleanup para 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

  1. Declaramos mat como NULL e i para controlar o progresso da alocação.
  2. Alocamos o vetor de ponteiros com malloc. Se falhar, perror e goto cleanup.
  3. No laço, alocamos cada linha. Se uma falhar, perror e goto cleanup.
  4. No rótulo cleanup, liberamos as linhas já alocadas. Como i é o índice da linha que falhou, liberamos de i-1 até 0.
  5. Liberamos o vetor de ponteiros e retornamos NULL.
  6. Se tudo der certo, retornamos mat antes 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] para j >= i: acessa ponteiros não inicializados, causando segmentation fault.
  • Esquecer de liberar mat no cleanup: vazamento do vetor de ponteiros.
  • Usar goto para 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.