Puoi anche strutturare la tua lista prevedendo un "nodo sentinella"
http://en.wikipedia.org/wiki/Linked_...sentinel_nodes
cioè di fatto un nodo che costituisce la testa "fisica" della lista pur senza farne realmente parte. In questo modo, ciascun nodo della lista (compresa la testa) sarà sempre il "nodo prossimo" di un altro nodo, eliminando di fatto l'anomalia dell'inserimento in testa della lista e la necessità di modificare la firma della funzione di modifica introducendo come parametro un doppio puntatore. Ovviamente la presenza di un nodo sentinella richiede inevitabilmente altro spazio in memoria: questo potrebbe essere poco conveniente nel caso in cui dovessi gestire molte liste di pochi nodi, pertanto fai le tue considerazioni.
Un'altra soluzione potrebbe consistere nel definire un tipo "lista" come un contenitore avente, tra gli altri, un campo "testa": in questo modo alle varie funzioni che operano sulla lista puoi passare un puntatore (singolo) a questo contenitore e poi eventualmente modificarne il puntatore alla testa internamente.
Un esempio rapido e non testato (per rendere il concetto), riadattando il tuo codice:
codice:typedef struct _elemento { int inf; struct _elemento *next; } _elemento; typedef struct lista { _elemento *testa; /* eventuali altri campi, ad esempio... */ _elemento *coda; int n_elementi; } lista; ... void MODIFICA(lista *L1) { _elemento *app; if (L1->testa->inf % 2 == 0) { printf("testa pari \n"); app = (_elemento *)malloc(sizeof(_elemento)); app->inf = (L1->testa->inf * 2); app->next = L1->testa; L1->testa = app; /*aggiorniamo la testa*/ printf("L1->testa->inf e' %d \n",L1->testa->inf); } return; }