Mi chiedevo quale sarebbe stato il miglior approcio per allocare / deallocare più matrici dinamiche unidimensionali in C. Questo all'inizio sembra facile, tuttavia, per me è diventato problematico Considre il seguente programma di esempio, che illustra il mio problema:
#include <stdio.h>
#include <stdlib.h>
#define N 10
int my_func(size_t n);
int main(void)
{
int ret = my_func(N);
printf("%d\n", ret);
return 0;
}
int my_func(size_t n)
{
double *x = malloc(n * sizeof (double));
if (x==NULL) return 0;
double *y = malloc(n * sizeof (double));
if (y==NULL) { free(x); return 0; }
double *z = malloc(n * sizeof (double));
if (z==NULL) { free(x); free(y); return 0;}
/* some computations */
free(x); free(y); free(z);
return 1;
}
Assegnazione e controllo di x
, è semplice. Tuttavia, se l'allocazione di y
fallisce, è necessario liberare x
. Se c'è un ulteriore array, come z
nell'esempio, e la sua allocazione fallisce, ci si deve preoccupare di x
e y
. E come sempre, tutta la memoria deve essere liberata alla fine della funzione. In generale, il controllo di un'allocazione fallita da qualche parte nel programma richiede di occuparsi di tutti i blocchi di memoria allocati in precedenza.
Ho pensato che sarebbe stato "più semplice" automatizzare la deallocazione di tutti i blocchi di memoria allocati in precedenza, così ho trovato la seguente implementazione che utilizza un "registro di memoria" per memorizzare i puntatori ai blocchi di memoria allocati.
#include <stdio.h>
#include <stdlib.h>
#define N 10
#define N_BLOCKS 3
double *mem_reg[] = { NULL, NULL, NULL };
void clean_up(void);
int my_func(size_t n);
int main(void)
{
int ret = my_func(N);
printf("%d\n", ret);
return 0;
}
int my_func(size_t n)
{
double *x = malloc(n * sizeof (double));
if (x!=NULL) mem_reg[0] = x; else goto fail;
double *y = malloc(n * sizeof (double));
if (x!=NULL) mem_reg[1] = y; else goto fail;
double *z = malloc(n * sizeof (double));
if (x!=NULL) mem_reg[2] = z; else goto fail;
/* some computations */
clean_up();
return 1;
fail:
clean_up();
return 0;
}
void clean_up(void)
{
for (size_t i=0; i<N_BLOCKS; i++)
{
if (mem_reg[i] != NULL)
free(mem_reg[i]);
}
}
L'advanatge del secondo esempio è che esiste un punto di uscita singolo in my_func
definito e l'etichetta fail
. Quindi, anche se dovessi verificare alcuni errori nei calcoli (non mostrati negli esempi), potrei semplicemente goto fail
per pulire facilmente tutte le allocazioni dinamiche. Lo svantaggio è che il codice del secondo esempio non è più semplice del codice del primo esempio.
Potresti aver riconosciuto che non ho molta esperienza in C, quindi questa domanda. C'è un vantaggio in uno di entrambi gli esempi, che non ho visto? Allora quale è da preferire. O c'è anche un modo migliore?