[C] Intersezione tra due liste, errore di segmentazione

di il
2 risposte

[C] Intersezione tra due liste, errore di segmentazione

Ciao a tutti, ho scritto questa funzione, che ha il compito di riunire gli elementi comuni a due liste in una terza, ma il terminale mi segnala un errore di segmentazione (core dump creato) che proprio non riesco a trovare. Il resto del programma viene compilato ed eseguito correttamente, quindi sono sicuro che il problema sia proprio qui! Grazie a tutti in anticipo
nodo_t* intersezione(nodo_t *l1, nodo_t *l2)
{
	nodo_t 	*l3, *new;
	int acc=0;

	for( ; l1!=NULL; l1=l1->next){
		for( ; l2!=NULL; l2=l2->next) {
			if(l1->n==l2->n)			
				acc++;
			if(acc==1 && l1->n==l2->n) {
				l3=(nodo_t*)malloc(sizeof(nodo_t));
				l3->n=l1->n;
				l3->next=(nodo_t*)malloc(sizeof(nodo_t));
				new=l3->next;
			}
			if(acc>1 && l1->n==l2->n){
				new->n=l1->n;
				new->next=(nodo_t*)malloc(sizeof(nodo_t));
				new=new->next;
			}
		}
		
	}
	new->next=NULL;
	return l3;
}
Vi posto anche la struttura della lista
typedef struct nodo {
	int n;
	struct nodo *next;
}nodo_t;

2 Risposte

  • Re: [C] Intersezione tra due liste, errore di segmentazione

    Ciao, il segmentation fault indica che il tuo programma ha tentato di accedere ad un'area di memoria che non gli è riservata, quindi di fatto si tratta di un problema coi puntatori.
    Guardando il tuo codice, infatti, puoi vedere che la prima volta in cui "l1->n == l2-> n" crei un giustamente un nuovo elemento l3 e gli assegni il valore n. Dopodiché, però, ti prepari già un nuovo elemento (cioè l3->next, che conterrà dei valori casuali), e questo è sbagliato perché non sai neanche se ci sarà un elemento successivo. Ad esempio se le liste hanno in comune 1 solo elemento, la lista l3 dovrà contenere 1 elemento, non 2.
    L'istruzione che ti causa il segmentation fault, però, è new->next=NULL;. Infatti poiché new punta a l3->next (che contiene valori casuali), quando fai new->next = NULL tenti di accedere ad un'area di memoria con indirizzo "casuale", cosa che ti causa il segmentation fault.

    Il mio consiglio, quindi, è quello di crearti il nuovo elemento solo quando ne hai bisogno ed appenderlo in coda alla lista (puoi sfruttare una variabile che punti sempre all'ultimo elemento della lista l3, un po' come hai fatto con new).

    Inoltre c'è un altro errore più subdolo: nei 2 cicli usi direttamente le variabili l1 ed l2, perdendo definitivamente (all'interno della funzione) i riferimenti agli inizi delle 2 liste. Per la lista l1 questo non è un problema, ma per l2 sì, in quanto ad ogni iterazione del ciclo su l1 devi ricominciare a scandire l2 dall'inizio. Per cui devi usare delle variabili indice:
    
    nodo_t* i;
    nodo_t* j;
       for(i=l1; i!=NULL; i=i->next){
          for(j=l2 ; j!=NULL; j=j->next) {
              ...
    
    Inoltre da quanto ho capito sfrutti la variabile acc esclusivamente per distinguere il caso in cui l3 sia vuoto (cioè la prima occorrenza in cui l1->n == l2->n) oppure no. In questo caso potresti semplicemente controllare se l3 è NULL oppure no:
    
    nodo_t* intersezione(nodo_t* l1, nodo_t* l2) {
        nodo_t* l3 = NULL;
        nodo_t* tail = NULL;
        ...
    
            if (i->n == j->n) {
                if (l3 == NULL) {
                    l3 = (nodo_t*) malloc(sizeof(nodo_t));
                    l3->n = i->n;
                    l3->next = NULL;
                    tail = l3; 
                } else {
                    // tail punta all'ultimo elemento valido di l3
                    nodo_t* tmp = (nodo_t*) malloc(sizeof(nodo_t));
                    tmp->n = i->n;
                    tmp->next = NULL;
                    tail->next = tmp;
                    tail = tail->next;
                }
                /*
                  * A questo punto se non ti servono gli elementi
                  * eventualmente ripetuti e' inutile continuare a controllare
                  * i successivi elementi, perche' ho gia' trovato
                  * un elemento di l2 uguale all'elemento corrente di l1.
                  * Per cui posso passare al successivo elemento di l1.
                  * Se, invece, vuoi anche gli elementi ripetuti il break
                  * va rimosso.
                  */
                  break;
            }
    }
    
  • Re: [C] Intersezione tra due liste, errore di segmentazione

    Grazie mille, molto chiaro ed esauriente!
Devi accedere o registrarti per scrivere nel forum
2 risposte