paulo1205
(usa Ubuntu)
Enviado em 19/09/2017 - 09:21h
Você parece ter entendido certo o caso de fazer com com
1+m alocações/desalocações, pois suas funções funcionam. Apesar disso, é possível fazer algumas melhorias:
— O comando
return não exige uso de parênteses. Você pode dizer apenas “
return NULL;” ou “
return v;”.
— Não é usual imprimir mensagens de diagnóstico dentro de uma função de alocação de recursos (ou outra função qualquer numa biblioteca de funções utilitárias). Em vez disso, o normal é sinalizar o erro (o que você já está fazendo, ao retornar
NULL na alocação ou não-
NULL na desalocação), e deixar que quem chama a função decida como tratar a condição sinalizada. Se for necessário passar mais detalhes, você pode recorrer à variável global
errno ou a outra variável global ou estática com sentido semelhante, que você mesmo pode criar.
— Em C não é necessário nem desejável ter a conversão de tipos explícita entre o valor retornado por
malloc()/
calloc()/
realloc(), que é do tipo
void *, para outro tipo de ponteiro, pois a linguagem realiza essa conversão implicitamente. Somente seria necessário ter a conversão explícita se você estivesse usando C++. Contudo, se você estivesse usando C++, provavelmente não deveria usar as funções de alocação herdadas do C, mas sim um dos operadores de alocação nativos do C++ ou uma das classes de
containers da STL (ou de outro
framework, como Boost ou Qt).
— Se acontecer uma falha após a primeira alocação, você está retornando um ponteiro nulo, mas não está limpando as áreas que já haviam sido parcialmente alocadas. Desse modo, seu código tem um
bug latente de
memory leak. O certo seria você liberasse as alocações anteriores caso ocorra alguma falha após a primeira alocação.
— Ao liberar memória, geralmente não se usa a forma “
ponteiro_a_ser_liberado=funcao_de_liberacao(ponteiro_a_ser_liberado ...)”, mas sim algo como “
funcao_de_liberacao(ponteiro_a_ser_liberado...)” ou “
funcao_de_liberacao(&ponteiro_a_ser_liberado...)”.
— O parâmetro
n não é efetivamente usado pela função de liberação. Desse modo, ele poderia ser suprimido.
No código acima, fica muito evidente o fraco acoplamento entre a matriz (que é um um vetor de vetores dinamicamente alocados) e suas dimensões, principalmente na desalocação. É necessário manter informações sobre a dimensão numa variável externa separada desde a alocação até a desalocação. Num programa longo, seria fácil cometer um erro de edição ou de digitação, e acabar informando uma dimensão errada.
O uso de apenas duas alocações ajuda a contornar essa dificuldade. Ela se baseia no fato de que cada elemento
v[i] (com
i entre
0 e
m-1) contém um endereço (ponteiro) de um array de
n valores. No caso anterior, cada um desses endereços era gerado a partir de uma alocação explícita de espaço para
n elementos, mas nada obriga que assim seja. Você poderia fazer uma alocação de um blocão grande o suficiente para todos os elementos da matriz, e alimentar o
vetor de vetores com endereços de posições intermediárias dentro desse blocão.
Esse arranjo tem duas vantagens: desperdiça menos memória com
overhead de alocação (tipicamente cada alocação requer um número de bytes a mais, além daqueles que foram solicitados explicitamente, para que as funções
free() e
realloc() saibam tratar aquele ponteiro nos casos de liberação e realocação, respectivamente) e libera o usuário de ter de carregar a informação de dimensões até a desalocação.
Existem desvantagens também. A principal, entre as de que consigo pensar agora, é que eventuais mudanças de dimensão da matriz podem ser mais trabalhosas, requerendo mais código explícito, do que com um ponteiro separadamente alocado para cada linha.
ATENÇÃO: Quando você implementar o exercício 4, lembre-se de que ponteiros alocados de um jeito não podem ser passados à função de desalocação do outro jeito. À alocação feita em
1+m passos tem de corresponder a desalocação em
1+m passos, que vai receber como parâmetros a matriz e o valor de
m, e à alocação feita em 2 passos deve corresponder a desalocação em dois passos, que recebe apenas a matriz como parâmetro.