In realtà ti ho già detto come la penso, ossia che al fine di rendere il codice più chiaro e generico hai bisogno di implementare una funzione cancella_nodo() finalizzata all'eliminazione di un generico nodo. A tal proposito ti ho già dato qualche input, ma evidentemente devo essere più esplicito...
Ipotizziamo di avere una funzione del genere:
void cancella_nodo(nodo *curr);
finalizzata ad eliminare il nodo curr. Cancellare il nodo risulta banale, invece collegare il nodo precedente a curr con quello ad esso successivo risulta impossibile in quanto non abbiamo modo di accedere al membro next del nodo precedente.
Possiamo quindi ipotizzare di utilizzare ugualmente una funzione del tipo:
void cancella_nodo(nodo *prec);
finalizzata però ad eliminare il nodo successivo a prec. In questo caso il collegamento tra il nodo precedente e successivo al nodo da eliminare risulta fattibile, ma sorge un altro problema, ossia non possiamo eliminare il nodo iniziale, in quanto ovviamente non preceduto da un altro nodo.
Bisogna quindi distinguere l'eliminazione del primo elemento della lista (caso1) dall'eliminazione di uno degli elementi successivi (caso2), e quindi sarà anche necessario escogitare un modo per comunicare alla funzione se ci troviamo nel primo o nel secondo caso. Come fare? Possiamo per esempio ricorrere a qualcosa del genere:
void cancella_nodo(nodo *testa, nodo *prec);
dove prec è il nodo precedente al nodo da eliminare e testa rappresenta ovviamente la testa della lista. Il caso1 potrebbe per esempio essere riconosciuto dal fatto che prec sia uguale a NULL.
Resta però un ultimo problema: come aggiornare la testa della lista nel caso1? Bisogna quindi modificare il prototipo della funzione nel seguente modo:
nodo* cancella_nodo(nodo *testa, nodo *prec);
in modo che la funzione ritorni la testa della lista, eventualmente aggiornata se ci troviamo nel caso1.
L'implementazione della funzione la lascio a te, ma ti mostro come ti semplificherebbe la vita l'utilizzo di un puntatore doppio:
void cancella_nodo(nodo **curr)
{
nodo *temp = *curr;
*curr = (*curr)->next;
free(temp);
}
Come vedi: semplice, conciso, nessun valore di ritorno e nessuna distinzione tra caso1 e caso2!
Ovviamente una volta implementata la funzione cancella_nodo(), cancellare i nodi dispari risulterà banale!