Ciao, innanzitutto, al fine di rendere il codice più chiaro e leggibile, ti consiglio di rispettare l'indentazione e la spaziatura, e di racchiudere il corpo delle istruzioni di controllo all'interno di parentesi graffe anche se costituite da una singola riga di codice.
Partiamo da quelle che ritengo essere le basi per un esercizio sulle liste, ossia due funzioni come si deve che aggiungono elementi in testa e in coda alla lista.
Dalla tua versione delle suddette funzioni e dal modo in cui le richiami mi viene da pensare che tu abbia le idee un po' confuse al riguardo. Per esempio la funzione testa() perché accetta come argomento un puntatore doppio e allo stesso tempo ritorna un puntatore?
Detto questo io farei semplicemente qualcosa del genere:
#include <stdio.h>
#include <stdlib.h>
typedef struct nodo_
{
int data;
struct nodo_ *next;
} nodo;
void aggiungi_in_testa(nodo **p, int info)
{
nodo *nuovo = (nodo*)malloc(sizeof(nodo));
nuovo->data = info;
nuovo->next = *p;
*p = nuovo;
}
void aggiungi_in_coda(nodo **p, int info)
{
while(*p)
{
p = &(*p)->next;
}
aggiungi_in_testa(p, info);
}
void stampa_lista(nodo *p)
{
while(p)
{
printf("%d ", p->data);
p = p->next;
}
}
int main()
{
nodo* l = NULL;
aggiungi_in_coda(&l, 3);
aggiungi_in_testa(&l, 2);
aggiungi_in_coda(&l, 4);
aggiungi_in_testa(&l, 1);
aggiungi_in_coda(&l, 5);
stampa_lista(l);
}
Per quanto riguarda il resto dell'esercizio sinceramente non ho ancora capito cosa stai cercando di fare. Potresti essere più chiaro e magari fare un esempio concreto?