Filtro
La funzione di filtro prende in ingresso un array e ritorna un array con alcuni elementi dell'array di ingresso.
Questa tipologia di funzione presenta un problema nuovo: prima di invocare la funzione, non so quanto sarà lungo l'array di output. Per risolvere il problema, posso usare l'allocazione di memoria dinamica, cioè la heap.
Gestione della heap
La gestione della heap è responsabilità del programmatore, che deve quindi assicurarsi che tutto il ciclo di vita della variabile sia corretto.
Nota: nella stack non dobbiamo preoccuparci del ciclo di vita della variabile perché è gestita automaticamente dal compilatore.
Il ciclo di vita è formato da:
- creazione: per creare una variabile nella heap, uso la funzione di sistema
malloc()
che prende in ingresso il numero di byte che voglio riservare in memoria; malloc ritorna un puntatore alla variabile appena creata - manipolazione: posso manipolare l'area di memoria in diversi modi, in particolare a noi interessa poter cambiare il numero di byte della memoria riservata, che si ottiene con la funzione di sistema
realloc()
- distruzione: la memoria nella heap si libera con la funzione di sistema
free()
Funzione di filtro
Detto questo, torniamo ora alla nostra funzione di filtro.
La struttura di una funzione di filtro è la seguente:
// voglio ritornare un array con solo i valori maggiori o uguali a 18
int* maggiorenne(int arr_in[], int n, int* counter) {
// all'inizio l'array di output ha stessa dimensione di arr_in
int* arr_out = malloc(sizeof(int)*n);
for (int i = 0; i < n; i++){
if (arr_in[i]>18) {
arr_out[*counter] = arr_in[i];
(*counter)++;
}
}
// realloco la memoria in modo da occupare solo lo spazio necessario
arr_out = realloc(arr_out,sizeof(int)* (*counter) );
return arr_out;
}
Posso chiamare questa funzione nel seguente modo:
int main() {
int x[] = {10, 20, 30};
int z_counter = 0;
int* z = maggiorenne(x,3,&z_counter);
printf("Numero di elementi filtrati: %d\n",z_counter);
for (int i = 0; i < z_counter; i++){
printf("Elemento %d filtrato: %d\n",i,z[i]);
}
free(z); // devo distruggere z quando non mi serve più!
return 0;
}
Si può visualizzare la gestione della memoria di questa funzione con PythonTutor:
Cose a cui prestare attenzione:
- il tipo degli elementi dell'array di input deve essere lo stesso del tipo degli elementi dell'array di output
- la lunghezza dell'array di input varia da un minimo di zero (array vuoto) ad un massimo della lunghezza dell'array di input
- ricordarsi sempre di distruggere la variabile (liberare la memoria) quando non uso più la variabile creata nella malloc, altrimenti genero un bug chiamato memory leak.