Problema rimozione elemento da lista [C]

di il
35 risposte

Problema rimozione elemento da lista [C]

Ciao a tutti sto implementando un programma che tra le altre cose ti permette di rimuovere un elemento da una lista presa da un file digitandolo da tastiera.. Il mio problema è che non riesco ad eliminare l'elemento in questo caso.. ho provato altre varianti, ma nessuna corretta, in quanto mi eliminava tutti gli elementi dal file.. vi posto l'ultima versione del codice..
(in questo non elimina nulla)
void rimuovi_da_lista (p_elemento nodo){

	/*apro il file in scrittura*/
	fp = fopen("lista.txt", "a");

	printf("Inserisci il numero da cancellare\n");
	scanf("%s %lg %lg", id, &reale, &immaginario);
	while(fscanf(fp, "%s %lg %lg", id, &reale, &immaginario) != EOF ) {
		if((strcmp(nodo->id, id) == 0) && (nodo->reale == reale) &&(nodo->immaginario == immaginario)) {

			nodo = nodo->next;
			free(nodo);
						
		}else{
			printf("Il numero inserito non esiste\n");
			exit(2);
		}
	}
}
Grazie

35 Risposte

  • Re: Problema rimozione elemento da lista [C]

    Te lo dico male ma in maniera intuitiva: devi capire in anticipo se il nodo che vuoi eliminare è il prossimo, nel qual caso lo "salti" (cioè colleghi il nodo attuale con il successivo di quello da eliminare) e poi fai la free. Se invece sei già sul nodo da eliminare... è troppo tardi! Questo perché non hai più a disposizione il puntatore al nodo precedente.
  • Re: Problema rimozione elemento da lista [C]

    minomic ha scritto:


    Te lo dico male ma in maniera intuitiva: devi capire in anticipo se il nodo che vuoi eliminare è il prossimo, nel qual caso lo "salti" (cioè colleghi il nodo attuale con il successivo di quello da eliminare) e poi fai la free. Se invece sei già sul nodo da eliminare... è troppo tardi! Questo perché non hai più a disposizione il puntatore al nodo precedente.
    Praticamente nel controllo dell'if ci devo mettere un "->next" dopo il nodo che sto puntando adesso?
  • Re: Problema rimozione elemento da lista [C]

    Esatto. Poi ovviamente devi trattare in modo separato il caso in cui il nodo da eliminare sia il primo della lista. Questo perché il nodo di testa non è il next di nessun altro nodo.
  • Re: Problema rimozione elemento da lista [C]

    minomic ha scritto:


    Esatto. Poi ovviamente devi trattare in modo separato il caso in cui il nodo da eliminare sia il primo della lista. Questo perché il nodo di testa non è il next di nessun altro nodo.
    Si a quello ci avevo già pensato, però anche modificando con i vari next il codice non mi elimina comunque il nodo
    La free che faccio va comunque di nodo giusto?
  • Re: Problema rimozione elemento da lista [C]

    Adesso non ho molto tempo per provare il codice, però ad occhio direi
    
    nodo->next = nodo->next->next;
    
    e poi la free che va fatta su una copia del nodo da eliminare. Comunque, ripeto, non riesco a provare il codice. Fai qualche esperimento e vedrai che ci riesci.
  • Re: Problema rimozione elemento da lista [C]

    minomic ha scritto:


    Adesso non ho molto tempo per provare il codice, però ad occhio direi
    
    nodo->next = nodo->next->next;
    
    e poi la free che va fatta su una copia del nodo da eliminare. Comunque, ripeto, non riesco a provare il codice. Fai qualche esperimento e vedrai che ci riesci.
    Okok grazie per il consiglio adesso ci smadonno un po'
  • Re: Problema rimozione elemento da lista [C]

    minomic ha scritto:


    Adesso non ho molto tempo per provare il codice, però ad occhio direi
    
    nodo->next = nodo->next->next;
    
    e poi la free che va fatta su una copia del nodo da eliminare. Comunque, ripeto, non riesco a provare il codice. Fai qualche esperimento e vedrai che ci riesci.
    Ho provato a cambiare tutto quello che mi avevi detto.. ma ancora non mi cancella nulla, cos'altro potrebbe essere?
    Per fare una copia del nodo da eliminare mi basta dichiarare un puntatore così?:
    void rimuovi_da_lista(p_elemento *p_lista)
    {
       p_elemento temp = *p_lista;
       [...]
    }
    
  • Re: Problema rimozione elemento da lista [C]

    Mentre aspettavo la tua risposta avevo preparato il codice completo (a meno di qualche mia svista, sempre possibile!). Provo a postartelo, così lo guardi e ci fai sapere se hai qualche dubbio.
    
    #include <stdio.h>
    #include <stdlib.h>
    
    
    typedef struct nodo_t {
    	int val;
    	struct nodo_t* next;
    } Nodo;
    
    typedef Nodo* Lista;
    
    Lista aggiungi_testa(Lista L, int n_val) {
    	Nodo* nuovo_nodo = malloc(sizeof(Nodo));
    	nuovo_nodo->val = n_val;
    	nuovo_nodo->next = L;
    	return nuovo_nodo;
    }
    
    void stampa_lista(Lista l) {
    	for(; l; l = l->next) {
    		printf("%d  ", l->val);
    	}
    	printf("\n");
    }
    
    Lista elimina_valore(Lista L, int elim) {
    	if(L == NULL) return L;
    	Nodo* tmp;
    
    	// eliminazione in testa
    	if(L->val == elim) {
    		tmp = L->next;
    		free(L);
    		return tmp;
    	}
    
    	Lista copia = L;
    
    	while(copia->next && copia->next->val != elim) {
    		/* se il seguente non ha un seguente
    		 * abbiamo finito: l'elemento non e'
    		 * presente nella lista */
    		if(!copia->next->next)
    			return L;
    		copia = copia->next;
    	}		
    
    	tmp = copia->next;
    	copia->next = copia->next->next;
    	free(tmp);
    	return L;
    }
    
    
    int main(int argc, char const *argv[])
    {
    	Lista L = NULL;
    	int i;
    	for(i=0; i<10; ++i) {
    		L = aggiungi_testa(L, i);
    	}
    
    	stampa_lista(L);
    	L = elimina_valore(L, 5);
    	stampa_lista(L);
    	L = elimina_valore(L, 11);
    	stampa_lista(L);
    	L = elimina_valore(L, 0);
    	stampa_lista(L);
    	L = elimina_valore(L, 9);
    	stampa_lista(L);
    
    	return 0;
    }
    
    Nota: in questa versione semplice viene cancellato solo il primo nodo che coincide con il valore da eliminare. Se invece vuoi cancellarli tutti, allora dovrai fare qualche piccola modifica.
  • Re: Problema rimozione elemento da lista [C]

    minomic ha scritto:


    Mentre aspettavo la tua risposta avevo preparato il codice completo (a meno di qualche mia svista, sempre possibile!). Provo a postartelo, così lo guardi e ci fai sapere se hai qualche dubbio.
    
    #include <stdio.h>
    #include <stdlib.h>
    
    
    typedef struct nodo_t {
    	int val;
    	struct nodo_t* next;
    } Nodo;
    
    typedef Nodo* Lista;
    
    Lista aggiungi_testa(Lista L, int n_val) {
    	Nodo* nuovo_nodo = malloc(sizeof(Nodo));
    	nuovo_nodo->val = n_val;
    	nuovo_nodo->next = L;
    	return nuovo_nodo;
    }
    
    void stampa_lista(Lista l) {
    	for(; l; l = l->next) {
    		printf("%d  ", l->val);
    	}
    	printf("\n");
    }
    
    Lista elimina_valore(Lista L, int elim) {
    	if(L == NULL) return L;
    	Nodo* tmp;
    
    	// eliminazione in testa
    	if(L->val == elim) {
    		tmp = L->next;
    		free(L);
    		return tmp;
    	}
    
    	Lista copia = L;
    
    	while(copia->next && copia->next->val != elim) {
    		/* se il seguente non ha un seguente
    		 * abbiamo finito: l'elemento non e'
    		 * presente nella lista */
    		if(!copia->next->next)
    			return L;
    		copia = copia->next;
    	}		
    
    	tmp = copia->next;
    	copia->next = copia->next->next;
    	free(tmp);
    	return L;
    }
    
    
    int main(int argc, char const *argv[])
    {
    	Lista L = NULL;
    	int i;
    	for(i=0; i<10; ++i) {
    		L = aggiungi_testa(L, i);
    	}
    
    	stampa_lista(L);
    	L = elimina_valore(L, 5);
    	stampa_lista(L);
    	L = elimina_valore(L, 11);
    	stampa_lista(L);
    	L = elimina_valore(L, 0);
    	stampa_lista(L);
    	L = elimina_valore(L, 9);
    	stampa_lista(L);
    
    	return 0;
    }
    
    Nota: in questa versione semplice viene cancellato solo il primo nodo che coincide con il valore da eliminare. Se invece vuoi cancellarli tutti, allora dovrai fare qualche piccola modifica.
    Grazie ma forse mi sono spiegato male io, il mio è un problema un po' diverso, la lista io la carico da file e tramite input da tastiera devo permettere la rimozione di numeri complessi nel formato "z"(stringa) "x"(double) "y"(double) già presenti nella lista e l'inserimento di nuovi numeri dello stesso formato.Il problema su cui mi sono bloccato è che le mie funzioni, per l'eliminazione sia del primo elemento che per gli altri elementi generici non funzionano, a me la logica sembra corretta ma a quanto pare non riesco a far puntare i puntatori dove voglio e inoltre il codice mi compila senza errori quindi non so neanche dove cercare gli errori.

    Ti mando il codice che ho modificato:
    void rimuovi_da_lista(p_elemento *p_lista)
    {
       p_elemento temp = *p_lista;
    
       fp = fopen("lista.txt", "a");
       printf("Inserisci il numero da cancellare\n");
       scanf("%s %lg %lg", id, &reale, &immaginario);
       
       if((strcmp(temp->next->id, id) == 0) && (temp->next->reale == reale) &&(temp->next->immaginario == immaginario))   {
          *p_lista = temp->next;
          free(temp);
       }
       else
       {
         	while((strcmp(temp->next->id, id) != 0) && (temp->next->reale != reale) &&(temp->next->immaginario != immaginario) && temp->next != NULL)
          temp->next = temp->next->next;
       }
       fclose(fp);
    }
    
  • Re: Problema rimozione elemento da lista [C]

    Sì, so che il tuo problema era diverso... Io ti ho postato un esempio di come eliminare nodi da una lista. Quello che tu dovrai cambiare è il tipo di nodo (il mio aveva un solo int come valore, mentre tu avrai id, parte reale e parte immaginaria) e di conseguenza il controllo per vedere se un nodo deve essere eliminato oppure no.
    Quindi puoi utilizzare il codice che ti ho postato come base, e poi fare le modifiche necessarie. Altrimenti faccio tutto io!
  • Re: Problema rimozione elemento da lista [C]

    minomic ha scritto:


    Sì, so che il tuo problema era diverso... Io ti ho postato un esempio di come eliminare nodi da una lista. Quello che tu dovrai cambiare è il tipo di nodo (il mio aveva un solo int come valore, mentre tu avrai id, parte reale e parte immaginaria) e di conseguenza il controllo per vedere se un nodo deve essere eliminato oppure no.
    Quindi puoi utilizzare il codice che ti ho postato come base, e poi fare le modifiche necessarie. Altrimenti faccio tutto io!
    Non vorrei che facessi tutto te sopratutto perché vorrei capire dove sbaglio, ma il codice che ti ho postato sopra secondo te cosa c'è che non va? Perché nella mia testa dovrebbe funzionare così ma a quanto pare no..
  • Re: Problema rimozione elemento da lista [C]

    minomic ha scritto:


    Sì, so che il tuo problema era diverso... Io ti ho postato un esempio di come eliminare nodi da una lista. Quello che tu dovrai cambiare è il tipo di nodo (il mio aveva un solo int come valore, mentre tu avrai id, parte reale e parte immaginaria) e di conseguenza il controllo per vedere se un nodo deve essere eliminato oppure no.
    Quindi puoi utilizzare il codice che ti ho postato come base, e poi fare le modifiche necessarie. Altrimenti faccio tutto io!
    Ho provato ad adattare il tuo codice a quello che serviva a me, ma ancora non mi elimina il numero che inserisco da tastiera. Compila senza problemi e mi chiede di inserire il numero da eliminare, ma quando lo inserisco non elimina nulla. Provo a mandarti anche questo.
    Lista elimina_valore(Lista L) {
    
    	fp = fopen("lista.txt", "a");
    	if(L == NULL) return L;
    	Nodo* tmp;
    	
    	printf("Inserisci il numero da cancellare\n");
    	scanf("%s %lg %lg", id, &reale, &immaginario);
    
    	/* eliminazione in testa*/
       	if((strcmp(L->id, id) == 0) && (L->reale == reale) && (L->immaginario == immaginario)) {
          	tmp = L->next;
          	free(L);
          	return tmp;
       	}
    
       	Lista copia = L;
    
       	while(copia->next && ((strcmp(copia->next->id, id) != 0) && (copia->next->reale != reale) && (copia->next->immaginario != immaginario))) {
          		/* se il seguente non ha un seguente
           		* abbiamo finito: l'elemento non e'
           		* presente nella lista */
          		if(!copia->next->next)
             		return L;
          		copia = copia->next;
       	}      
    
       	tmp = copia->next;
       	copia->next = copia->next->next;
       	free(tmp);
       	return L;
    	fclose(fp);
    }
    
    Magari anche paragonando questo con quello vecchio mi puoi aiutare a capire dov'è l'errore.

    Nel main la funzione la richiamo così:
    int main (void){
    
    [...]
    
    elimina_valore(nodo);
    
    [...]
    }
  • Re: Problema rimozione elemento da lista [C]

    Se vuoi negare un AND tra diverse condizioni, allora devi dire che almeno una non è vera.
    Quindi se vuoi negare
    
    a && b && c
    
    devi scrivere
    
    !a || !b || !c
    
    Se invece scrivi
    
    !a && !b && !c
    
    stai chiedendo una cosa diversa, cioè che siano tutte false. Ma questo non è necessario.
  • Re: Problema rimozione elemento da lista [C]

    minomic ha scritto:


    Se vuoi negare un AND tra diverse condizioni, allora devi dire che almeno una non è vera.
    Quindi se vuoi negare
    
    a && b && c
    
    devi scrivere
    
    !a || !b || !c
    
    Se invece scrivi
    
    !a && !b && !c
    
    stai chiedendo una cosa diversa, cioè che siano tutte false. Ma questo non è necessario.

    Giusto, ho cambiato quel punto ma ancora non cancella niente. Il nostro problema penso sia o il free fatto su un nodo sbagliato, o i puntatori dopo il while, o forse anche il controllo.
    Non so proprio dove sto sbagliando.
Devi accedere o registrarti per scrivere nel forum
35 risposte