Visualizzazione dei risultati da 1 a 6 su 6
  1. #1

    [C] Problema puntatori a lista

    Salve a tutti Sono nuova nel forum e avrei bisogno di un aiuto con un esercizio di preparazione per un esame universitario.

    Devo definire le seguenti funzioni:
    1. una funzione iterativa che legge i dati dal file di testo e li carica in una lista dove ogni nodo contiene una dato strutturato idoneo a memorizzare gli elementi di una riga, oltre al puntatore al nodo successivo (gli elementi sono stringa, stringa, intero, stringa, intero, intero).
    2. Una funzione ricorsiva che stampa il contenuto della lista, visualizzando tutti i campi.
    3. Una funzione ricorsiva che, data la matricola di uno studente, stampa la somma dei crediti da lui acquisiti
    4. Una funzione iterativa che, dato il cognome di uno studente, crea una seconda lista contenente SOLO i dati degli studenti con tale cognome, eliminandoli dalla lista originaria.

    Questo è il programma che ho creato:
    codice:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define DIM 20
    
    struct element
    {
        char cognome[DIM];
        char nome[DIM];
        int matricola;
        char esame[DIM];
        int crediti;
        int voto;
    };
    
    struct persona
    {
        struct element info;
        struct persona *next;
    };
    
    typedef struct persona studente;
    typedef studente *list;
    
    list newnode()
    {
        return malloc(sizeof(studente));
    }
    
    list make_list()     //funzione 1
    {
        FILE *fp;
        list head = NULL, tail = NULL;
        char c[DIM], n[DIM], e[DIM];
        int m, cr, v;
        int i;
        
        fp = fopen("input-esame.txt", "r");
        
        if(fp != NULL)
        {
            i = 0;
            
            while(feof(fp) == 0)
            {
                fscanf(fp,"%s %s %d %s %d %d", &c, &n, &m, &e, &cr, &v);
            
                if(i==0)
                {
                    head = newnode();
                    strcpy(head->info.cognome, c);
                    strcpy(head->info.nome, n);
                    head->info.matricola = m;
                    strcpy(head->info.esame, e);
                    head->info.crediti = cr;
                    head->info.voto = v;
                    tail = head;
                }
                else
                {
                    tail->next = newnode();
                    tail = tail->next;
                    strcpy(tail->info.cognome, c);
                    strcpy(tail->info.nome, n);
                    tail->info.matricola = m;
                    strcpy(tail->info.esame, e);
                    tail->info.crediti = cr;
                    tail->info.voto = v;
                }
                i++;
            }
            tail->next = NULL;
            fclose(fp);
        }
        else
        {
            printf("Errore: file non trovato.\n");
            exit(1);
        }
        
        return head;
    }
    
    list printlist(list l)   //funzione 2
    {
        if(l != NULL)
        {
            printf("%s %s %d %s %d %d\n", l->info.cognome, l->info.nome, l->info.matricola, l->info.esame, l->info.crediti, l->info.voto);
            printlist(l->next);
        }
    }
    
    list printsomma(list l, int m, int sum)   //funzione 3
    {
        if(l != NULL)
        {
            if(l->info.matricola == m)
            {
                sum = sum + l->info.crediti;
                printsomma(l->next, m, sum);
            }
            else
                printsomma(l->next, m, sum);
        }
        else
            printf("Totale crediti: %d\n", sum);
    }
    
    list build_list(list *l, char c[])   //funzione 4
    {
        list p, q;
        list head = NULL, tail = NULL;
        
        while(*l != NULL)
        {
            if(strcmp((*l)->info.cognome, c) == 0)
            {
                p = newnode();
                p->info = (*l)->info;
                p->next = NULL;
                
                if(head == NULL)
                {
                    head = p;
                    tail = p;
                }
                else
                {
                    tail->next = p;
                    tail = p;
                }
                
                q = *l;
                *l = (*l)->next;
                free(q);
            }
            *l = (*l)->next;
        }
        return head;
    }
    
    int main()
    {
        list l1, l2;
        l1 = make_list();
        printlist(l1);
        
        int m;
        printf("Inserire matricola di cui calcolare i crediti totali:\t");
        scanf("%d", &m);
        printsomma(l1, m, 0);
        
        printf("\n");
        char c[DIM];
        printf("Inserire cognome dello studente da cercare:\t");
        scanf("%s", c);
        l2 = build_list(&l1, c);
        printlist(l2);
        
        printf("\n");
        printlist(l1);
    }
    Le funzioni 1, 2 e 3 funzionano correttamente, l'unico problema è la funzione 4 dove devo creare una nuova lista cancellando i nodi dalla lista originaria. Quando compilo il file .c non mi dà errori ma come output mi stampa la nuova lista creata senza l'ultimo nodo e quando cerco di stampare la lista originaria (quella dove non dovrebbero più esserci i nodi della nuova lista) non mi stampa nulla (quindi la lista è vuota e non ha nessun nodo).
    Non riesco a capire quale sia il problema

  2. #2
    Utente di HTML.it L'avatar di boots
    Registrato dal
    Oct 2012
    Messaggi
    1,626
    Secondo me ci sono due problemi:

    1. Se vuoi cancellare un elemento della lista, ti serve oltre al puntatore all'elemento corrente anche quello a precedente (a meno che non fai una lista doppiamente linkata). in questo modo la cancellazione diventa:
    codice:
    prev->next = current->next;
    free(current); // oppure lo aggiungi alla nuova lista
    2.Quando trovi l'elemento fai un doppio passo avanti

    codice:
    if(strcmp(...)){
        ...
       *l = (*l)->next; // vai al prossimo
        free(q);
    }
    *l = (*l)->next; // vai al prossimo (del prossimo)
    Come vedi nel caso trovi il nodo fai due volte *l = (*l)->next;. Usando il puntatore prev, ti basta assegnarlo a *l
    codice:
    if(strcmp(...)){
        ...
       *l = prev; // vai al precendente
        free(q);
    }
    *l = (*l)->next; // vai al prossimo
    PS: Ovviamente devi gestire il caso in cui devi cancellare la testa della lista
    Ultima modifica di boots; 12-01-2017 a 14:44

  3. #3
    Utente di HTML.it L'avatar di boots
    Registrato dal
    Oct 2012
    Messaggi
    1,626
    Un altra cosa: Tu passi un puntatore di puntatore (list *l) ed ad ogni ciclo vai a modificare il valore *l finchè non è null. Dato che è un puntatore vai a modificare direttamente l1 (a cui fai riferimento con *l) nel main. Di conseguenza l1 varrà null dopo l'esecuzione della buld_list()

  4. #4
    Ho provato a modificare la funzione in questo modo:
    codice:
    list build_list(list l, char c[])   //funzione 4
    {
        list p, q, n;
        list head = NULL, tail = NULL;
        
        if(l != NULL)
        {
            q = l;
            while(q->next != NULL)
            {
                if(strcmp(q->next->info.cognome, c) == 0)
                {
                    n = newnode();
                    n->info = q->info;
                    n->next = NULL;
                    
                    if(head == NULL)
                    {
                        head = n;
                        tail = n;
                    }
                    else
                    {
                        tail->next = n;
                        tail = n;
                    }
                    
                    p = q->next;
                    q->next = q->next->next;
                    free(p);
                }
                else 
                    q = q->next;
            }
            
            if(strcmp(l->info.cognome, c) == 0) //gestisco la testa della lista
            {
                n = newnode();
                n->info = q->info;
                n->next = NULL;
                    
                if(head == NULL)
                {
                    head = n;
                    tail = n;
                }
                else
                {
                    tail->next = n;
                    tail = n;
                }
                
                p = l;
                l = l->next;
                free(p);
            }
        }
        return head;
    }
    Questa volta mi elimina correttamente i nodi dalla prima lista, ma non crea la seconda lista con i nodi eliminati dalla prima (i nodi della seconda lista sono gli stessi della prima :/ ).
    (scusa il ritardo nella risposta)

  5. #5
    Utente di HTML.it L'avatar di boots
    Registrato dal
    Oct 2012
    Messaggi
    1,626
    Ho provato il tuo codice e in qualche modo funziona, solo due considerazioni:

    Se controlli q->next, quando ti crei il nodo per la nuova lista anche info deve puntare a quella di q->next:
    codice:
    n = newnode();
    n->info = q->next->info;
    // non n->info = q->info;
    n->next = NULL;
    Seconda cosa, nella tua prima versione passare il puntatore al puntatore è corretto perchè in caso di eliminazione in testa potevi modificare anche il puntatore del main.
    Ora quando fai
    codice:
     p = l;
     l = l->next;
     free(p);
    l è locale alla funzione. quindi quando fai l = l->next NON stai modificando l1 del main ma soltanto la copia nella build_list. Di conseguneza l1(main) continuerà a punatare all'elemento che hai "cancellato"

  6. #6
    Ho modificato la funzione seguendo i tuoi consigli:
    codice:
    list build_list(list *l, char c[])   //funzione 4
    {
        list p, q, n;
        list head = NULL, tail = NULL;
        
        if(*l != NULL)
        {
            q = (*l);
            while(q->next != NULL)
            {
                if(strcmp(q->next->info.cognome, c) == 0)
                {
                    n = newnode();
                    n->info = q->next->info;
                    n->next = NULL;
                    
                    if(head == NULL)
                    {
                        head = n;
                        tail = n;
                    }
                    else
                    {
                        tail->next = n;
                        tail = n;
                    }
                    
                    p = q->next;
                    q->next = q->next->next;
                    free(p);
                }
                else 
                    q = q->next;
            }
            
            if(strcmp((*l)->info.cognome, c) == 0) //gestisco la testa della lista
            {
                n = newnode();
                n->info = (*l)->info;
                n->next = NULL;
                    
                if(head == NULL)
                {
                    head = n;
                    tail = n;
                }
                else
                {
                    tail->next = n;
                    tail = n;
                }
                
                p = (*l);
                (*l) = (*l)->next;
                free(p);
            }
        }
        return head;
    }
    E ora funziona. Grazie mille

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.