Esercizio sulle Liste: eliminare un elemento

di il
10 risposte

Esercizio sulle Liste: eliminare un elemento

Ciao a tutti
sono alle prime armi in C e chiedo aiuto per un esercizio sulle liste dove mi chiede di eliminare un dato elemento da una lista e restituire il puntatore alla lista stessa. Ho provato a buttare giù qualche riga ma non funziona (l'errore che riscontro è Segmentation fault). Ecco il codice

list* elimina(list *l, int val){
    list *p;
    if (l == NULL) return NULL; //caso base, lista vuota
    if (((*l)->value == val)) { //altro caso base:
        p = (*l)->next; //l'elemento da eliminare e' il primo della lista
        free(l);
        return p;
    }
    else { //devo proseguire la ricerca
        (*l)->next = elimina((*l)->next, val); //elimino ricorsivamente dal resto della lista
        return l; //restituisco il puntatore alla lista
    }
}
e questa è la struct:

struct node { 
    int value;
    struct node *next; 
};
typedef struct node *list;
penso che il ragionamento sia giusto ma forse sbaglierò....
ringrazio in anticipo per le risposte

10 Risposte

  • Re: Esercizio sulle Liste: eliminare un elemento

    Usa I tag code per il codice
  • Re: Esercizio sulle Liste: eliminare un elemento

    oregon ha scritto:


    scusami hai ragione
  • Re: Esercizio sulle Liste: eliminare un elemento

    Come hai chiamato la funzione nel main?
    Edit: tieni conto che
    list = node*
    list* = node**
  • Re: Esercizio sulle Liste: eliminare un elemento

    Metto il codice così da fami capire meglio
    
    int main() {
        list root=NULL; 
        
        inserisci(90,&root);
        inserisci(45,&root);
        inserisci(4,&root);
        inserisci(8,&root);
        
        elimina_ric(&root,4);
        
        stampa(root);
     
        return 0;
    }
    
  • Re: Esercizio sulle Liste: eliminare un elemento

    Hai mischiato puntori a nodo (list) con doppi puntatori (list*). A quanto pare al compilatore C sta bene purché siano puntatori, mentre il compilatore C++ segnala errori.
    Premettendo che secondo me non ha senso ritornare list* e non list, ho provato ad aggiustarla così, ma non ho visto se funziona.
    
    list* elimina(list *l, int val){
        list p;
        if (*l == NULL) return l; //caso base, lista vuota
        if (((*l)->value == val)) { //altro caso base:
            p = (*l)->next; //l'elemento da eliminare e' il primo della lista
            free(*l);
            *l = p;
            return l;
        }
        else { //devo proseguire la ricerca
            elimina(&((*l)->next) , val); //elimino ricorsivamente dal resto della lista
            return l;
        }
    }
    
    
  • Re: Esercizio sulle Liste: eliminare un elemento

    Ti ringrazio per la risposta.. l'ho testata e funziona però non riesco a capire cos'ho sbagliato. Potresti farmi chiarezza su quei due punti che hai detto per favore?
    Ho un pò di confusione sulla questione dei puntatori
  • Re: Esercizio sulle Liste: eliminare un elemento

    Hai dichiarato:
    typedef struct node *list;

    Quindi list corrisponde a node* (puntatore a nodo)
    mentre list* corrisponde node** (puntatore a puntatore a nodo, detto anche puntatore doppio).
    Quindi:
    
    node* testa = (node*)malloc... ; //tipo list
    node** ppnodo = &testa; //tipo list*
    node* pnodo = *ppnodo; //ottengo un puntatore a node (list)
    node* pnext = (*ppnodo) -> next; //ancora puntatore a node (list)
    node nodo = **ppnodo; //ottengo un nodo
    int a = (**ppnode).val;
    int b = (*ppnode) -> val;
    
    Partendo dalla variabile p, essendo un puntatore temporaneo al nodo successivo, lo dichiaro node* (list) e non node** (list*).

    nella riga
    if (l == NULL) return NULL; //caso base, lista vuota
    Ma l (parametro di tipo list*) non è il puntatore al primo nodo, ma il puntatore al puntatore al primo nodo. Nel tuo caso l punta alla variabile nel main si chiama root, non a un nodo. Quindi se anche la lista è vuota, il puntatore alla testa è nullo, ma il puntatore al puntatore alla testa non è nullo (a meno chi tu non passi NULL come argomento).
    
    p = (*l)->next;
    
    Il puntatore al nodo successivo è di tipo list, non list*, per questo p va dichiarato list.
    
    free(l);
    
    Stessa cosa nel caso dell'if, per accedere al puntatore al nodo, devi usare *l, a meno che tu non voglia eliminare la variabile root.
    (*l)->next = elimina((*l)->next, val);
    Assegnazione sbagliata oltre che inutile. elimina restituisce node**, e tu la stai assegnando a un node*. Inoltre gli stai passando un node*, quando accetta un node**. Quindi gli devi dare l'indirizzo del puntatore al nodo successivo (cioè tipo node**), non un puntatore al nodo successivo (node*).
    Spero di essere stato esauriente, magari qualcun altro lo sa spiegare meglio.
  • Re: Esercizio sulle Liste: eliminare un elemento

    Sono sincera nel dire che hai spiegato meglio del mio professore! sei stato molto preciso e ti ringrazio
    Ho capito la tua spiegazione ma mi rimane un dubbio.
    Ho modificato come hai detto tu (perchè non ha senso avere list* ora che ho capito) in questo modo:
    
    list elimina(list *l, int val){...}
    
    e ti vorrei chiedere allora quale differenza troviamo nello scrivere quello che ho scritto sopra con quello seguente:
    
    list elimina(list l, int val){...}
    
    perchè entrambi funzionano correttamente... scusami se ti riempio di domande ma approfitto per togliermi questo dubbio
  • Re: Esercizio sulle Liste: eliminare un elemento

    Il problema sorge quando l'elemento da eliminare è il primo, in questo caso va modificato root per farlo puntare al successivo. Nel tuo caso questo già avviene, dal momento che hai passato root per indirizzo, quindi puoi anche restituire void o altro, ad esempio un puntatore all'elemento successivo a quello eliminato, ma sempre di tipo list, per assegnarlo ad una variabile di tipo nodo*.
    Se avessi dichiarato
    list elimina(list l, int val)
    La chiamata sarebbe dovuta avvenire così:
    
    root = elimina(root, 6);
    
    Per non perdere il valore del nuovo root (quello che gli hai passato è solo una copia). Mentre la funzione avrebbe dovuto ritornare *l.
    Conosci il passaggio di parametri per valore e per indirizzo? Ecco passare &root (tipo list*) vuol dire passare un puntatore per indirizzo. Il tipo list* ti serve solo nella funzione per poter accedere al root originale ed eventualmente modificarlo.
  • Re: Esercizio sulle Liste: eliminare un elemento

    Ho capito. Spiegazione ottima ti ringrazio!
Devi accedere o registrarti per scrivere nel forum
10 risposte