Visualizzazione dei risultati da 1 a 7 su 7
  1. #1
    Utente bannato
    Registrato dal
    Oct 2010
    Messaggi
    1,219

    [C]Fallimento realloc

    Salve ragazzi,prima dell' esame ho provato a scrivere il codice di una coda.
    Nulla di difficile,solo che mi fallisce sempre la reallocazione.
    Sto usando mingw32 su windows 7.
    codice:
    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <time.h>
    #include <stdbool.h>
    #include <string.h>
    
    
     
    typedef struct
    {
        char *nome;
        char *cognome;
    }studente;
    
    
    char *input (void);
    studente *enqueue (studente *pointer,int *size);
    void check (void *pointer);
    void swap (studente *first, studente *second);
    void print (studente *pointer, int *size);
    
                                                                                                                          
    int main(int agrc,char **agrv)
    {
        studente *pointer;
        int *size,i;
        pointer=(studente*)malloc(sizeof(studente));
        size=(int*)malloc(sizeof(int));
        *size=0;
        for(i=0;i<5;i++)
        {
            enqueue(pointer,size);
        }
        print(pointer,size);
        for(i=0;i<(*size);i++)
        {
            free(pointer[i].nome);
            free(pointer[i].cognome);
        }
        free(pointer);
        return 0;
    }
    
    
    char *input (void)
    {
        int ctr=0;
        int size=1;
        char *buffer;
        buffer=(char*)malloc(sizeof(char));
        check(buffer);
        while(ctr!=10)
        {
            ctr=getchar();
            if(ctr!=10)
            {
                buffer[size-1]=ctr;
                size++;
                buffer=(char*)realloc(buffer,size*sizeof(char));
            }
            else
                buffer[size-1]='\0';
        }
        return buffer;
    }
    
    studente *enqueue (studente *pointer,int *size)
    {
        int i;
        (*size)++;
        if((*size)>1)
            pointer=(studente*)realloc(pointer,(*size)*sizeof(studente));
        check(pointer);
        if(pointer==NULL)
        {
            printf("Errore di allocazione della memoria.\n");
            exit(0);
        }
        {
            for(i=(*size-1);i>1;i--)
            {
                pointer[i]=pointer[i-1];
            }
        }
        free(pointer[0].nome);
        free(pointer[0].cognome);
        printf("Inserisci nome:-->");
        pointer[0].nome=input();
        printf("Inserisci cognome:-->");
        pointer[0].cognome=input();
        return pointer;
    }
    
    void check (void *ptr)
    {
        if(ptr==NULL)
        {
            printf("Errore di allocazione della memoria.\n");
            exit(0);
        }
    }
    
    void swap (studente *first, studente *second)
    {
        studente *copy;
        copy=first;
        first=second;
        second=copy;
    }
    
    void print (studente *pointer, int *size)
    {
        int i;
        for(i=0;i<(*size);i++)
        {
            printf("Studente %d\t Nome: %s\nCognome: %s",i,pointer[i].nome,pointer[i].cognome);
        }
    }


    Praticamente con questo codice devo chiedere in input 5 volte nome e cognome,la struttura è nome+cognome,e alloco 5 volte la struttura,però capitano questi due comportamenti:
    -Delle volte dopo la terza struttura presa in input mi fallisce la realloc (ho previsto la stampa dell' errore);
    -Altre volte mi prende con successo tutti e 5 gli input,però appena li ha presi avviene il segmentation fault.
    Cosa potrebbe essere?

  2. #2

    Re: [C]Fallimento realloc

    codice:
    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <time.h>
    #include <stdbool.h>
    #include <string.h>
    
    
     
    typedef struct
    {
        char *nome;
        char *cognome;
    }studente;
    
    
    char *input (void);
    studente *enqueue (studente *pointer,int *size);
    void check (void *pointer);
    void swap (studente *first, studente *second);
    void print (studente *pointer, int *size);
    
                                                                                                                          
    int main(int agrc,char **agrv)
    {
        studente *pointer;
        int *size,i;
        pointer=(studente*)malloc(sizeof(studente));
        size=(int*)malloc(sizeof(int));
        *size=0;
        for(i=0;i<5;i++)
        {
            enqueue(pointer,size);
        }
        print(pointer,size);
        for(i=0;i<(*size);i++)
        {
            free(pointer[i].nome);
            free(pointer[i].cognome);
        }
        free(pointer);
        return 0;
    }
    
    
    char *input (void)
    {
        int ctr=0;
        int size=1;
        char *buffer;
        buffer=(char*)malloc(sizeof(char));
        check(buffer);
        while(ctr!=10)
        {
            ctr=getchar();
            if(ctr!=10)
            {
                buffer[size-1]=ctr;
                size++;
                buffer=(char*)realloc(buffer,size*sizeof(char));
            }
            else
                buffer[size-1]='\0';
        }
        return buffer;
    }
    
    studente *enqueue (studente *pointer,int *size)
    {
        int i;
        (*size)++;
        if((*size)>1)
            pointer=(studente*)realloc(pointer,(*size)*sizeof(studente));
        check(pointer);
        if(pointer==NULL)
        {
            printf("Errore di allocazione della memoria.\n");
            exit(0);
        }
        {
            for(i=(*size-1);i>1;i--)
            {
                pointer[i]=pointer[i-1];
            }
        }
        free(pointer[0].nome);
        free(pointer[0].cognome);
        printf("Inserisci nome:-->");
        pointer[0].nome=input();
        printf("Inserisci cognome:-->");
        pointer[0].cognome=input();
        return pointer;
    }
    
    void check (void *ptr)
    {
        if(ptr==NULL)
        {
            printf("Errore di allocazione della memoria.\n");
            exit(0);
        }
    }
    [/QUOTE]

    in enqueue dopo allocato il puntatore prima fai check e poi lo ricontrolli. Te lo potresti risparmiare (Era solo un appunto)

    Cmq il codice sembrebbe apposto.
    Ma quando dici che fallisce l'allocazione, esce semplicemente scrivend errore nell'allocazione oppure va in segment fault senza errore ?

  3. #3
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Ho esaminato un po' il codice e ci ho trovato alcune cose che non vanno, principalmente nella funzione enqueue(): in quella funzione il puntatore "pointer" potrebbe venire modificato dalla realloc() interna, alla fine c'è infatti una return di quel puntatore ma nel main() non ne salvi l'eventuale valore nuovo... sostituisci quindi la chiamata a enqueue() in main() con:

    codice:
    pointer = enqueue(pointer, size);
    (in realtà questa cosa si potrebbe risolvere molto più finemente passando a enqueue() un puntatore a puntatore ed eliminando il valore di ritorno, ma evito di farti invecchiare anzitempo).

    Fatto questo, considera il ciclo for che fai all'interno della stessa funzione enqueue() (per inciso, perché ci sono due parentesi graffe all'esterno? Non hanno nessuna utilità...): direi di sostituire la condizione i>1 con i>=1, altrimenti nel caso in cui gli elementi fossero due non ci sarebbe lo "shift in avanti" che intendi fare con quel ciclo, questo perché i partirebbe da 1 (2-1) e tale valore risulterebbe fin da subito non maggiore di 1.

    Infine, per un infame gioco di puntatori che mi risulta praticamente impossibile spiegare, direi di sostituire le operazioni di input di nome e cognome utilizzando buffer statici (diciamo di dimensione 30, se qualcuno ha un nome o un cognome più lungo si toglie dalle scatole ), altrimenti lasciando tutto così si crea la simpatica situazione per la quale alla fine tutti gli studenti si ritrovano con gli stessi nomi e cognomi (riducendo il discorso all'osso, questo succede perché copiando i puntatori alla fine ti ritrovi che tutti puntano alle stesse aree di memoria che hanno lo stesso contenuto). Tra l'altro, quell'operazione di input con una realloc() per ogni nuovo carattere forse eliminerà pure il problema dello spreco di memoria ma se si considera che per l'allocazione dinamica il processo fa una chiamata di sistema che mette in moto tutto un piccolo sistema solare, forse è meglio correre il rischio di sprecare qualche decina di byte.

    Infine rimane valida anche l'osservazione di lolide: fai due volte lo stesso controllo sul puntatore.

    Ti posto la versione modificata, se hai problemi fammi sapere. Ho eliminato la funzione swap() che non aveva alcuna utilità, nel caso reintroducila.
    Va poi da sé che, avendo reso statici i campi nome e cognome, ho eliminato le varie free() richiamate su di essi.

    codice:
    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <time.h>
    #include <stdbool.h>
    #include <string.h>
    
    #define MAX_LENGTH 30
    
    typedef struct
    {
        char nome[MAX_LENGTH];
        char cognome[MAX_LENGTH];
    }studente;
    
    
    void input (char []);
    studente *enqueue (studente *pointer,int *size);
    void check (void *pointer);
    void print (studente *pointer, int *size);
    
    
    int main(int agrc,char **agrv)
    {
        studente *pointer;
        int *size,i;
        pointer=(studente*)malloc(sizeof(studente));
        size=(int*)malloc(sizeof(int));
        *size=0;
        for(i=0;i<5;i++)
        {
            pointer = enqueue(pointer,size);
        }
    
        print(pointer,size);
        free(pointer);
        return 0;
    }
    
    
    void input (char *string)
    {
        fgets(string, MAX_LENGTH, stdin);
        string[strlen(string)-1] = '\0';
    }
    
    studente *enqueue (studente *pointer,int *size)
    {
        int i;
        (*size)++;
        if((*size)>1)
            pointer=(studente*)realloc(pointer,(*size)*sizeof(studente));
        check(pointer);
    
        for(i=(*size-1);i>=1;i--)
            {
                pointer[i]=pointer[i-1];
            }
    
        printf("Inserisci nome:-->");
        input(pointer[0].nome);
        printf("Inserisci cognome:-->");
        input(pointer[0].cognome);
        return pointer;
    }
    
    void check (void *ptr)
    {
        if(ptr==NULL)
        {
            printf("Errore di allocazione della memoria.\n");
            exit(0);
        }
    }
    
    void print (studente *pointer, int *size)
    {
        int i;
        for(i=0;i<(*size);i++)
        {
            printf("Studente %d\t Nome: %s\t Cognome: %s\n",i,pointer[i].nome,pointer[i].cognome);
        }
    }
    every day above ground is a good one

  4. #4
    Originariamente inviato da YuYevon
    Ho esaminato un po' il codice e ci ho trovato alcune cose che non vanno, principalmente nella funzione enqueue(): in quella funzione il puntatore "pointer" potrebbe venire modificato dalla realloc() interna, alla fine c'è infatti una return di quel puntatore ma nel main() non ne salvi l'eventuale valore nuovo... sostituisci quindi la chiamata a enqueue() in main() con:

    codice:
    pointer = enqueue(pointer, size);
    (in realtà questa cosa si potrebbe risolvere molto più finemente passando a enqueue() un puntatore a puntatore ed eliminando il valore di ritorno, ma evito di farti invecchiare anzitempo).
    Lui dopo fatto realloc ha assegnato il nuovo indirizzo al puntatore passato come parametro a enqueue, quindi non serve riprenderne il valore.

  5. #5
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Originariamente inviato da lolide
    Lui dopo fatto realloc ha assegnato il nuovo indirizzo al puntatore passato come parametro a enqueue, quindi non serve riprenderne il valore.
    No, non sarebbe servito se lui nella funzione avesse modificato il valore *puntato* dal puntatore, ma in realtà lui modifica il puntatore stesso e tale modifica non sarà visibile all'interno di main(). Per ottenere questo effetto dovrebbe riscrivere la funzione passando un puntatore a puntatore (richiamandola con &pointer).

    EDIT: aggiungo comunque che la realloc() non necessariamente modifica il puntatore, dipende se è possibile estendere il blocco di memoria allocato o no. In ogni caso, poiché la funzione *potrebbe* modificare il valore del puntatore, allora bisogna tenerne conto.
    every day above ground is a good one

  6. #6

    Re: [C]Fallimento realloc

    Originariamente inviato da ramy89
    Salve ragazzi,prima dell' esame ho provato a scrivere il codice di una coda.
    Nulla di difficile,solo che mi fallisce sempre la reallocazione.
    E' qui l'errore di base, per creare una queue non serve alcuna reallocazione...
    Fracty - The Fractal Generator



    If you cannot choose a concise name that expresses what the method does, it is possible that your method is attempting to perform too many diverse tasks.

  7. #7
    Utente bannato
    Registrato dal
    Oct 2010
    Messaggi
    1,219
    Poi ho visto che in realtà mi sbagliava sempre perchè non c' era bisogno di fare la riallocazione.
    Alla fine ho visto che ritornando il valore funzionava,solo che non mi stampava le stringhe.
    Per cui ho deciso di cambiare tattica,all' esame c' era il metodo delle liste concatenate,che non ho mai usato.
    C 'era una struttura del genere:
    codice:
    struct lista
    {
        int valore;
        nodo *next;
    }elem;
    La struttura elem è definita,next contiene il puntatore al prossimo elemento.
    Praticamente per scavalcare questo metodo,che a me pareva contorto e non riuscivo a fare,invece di aggiungere semplicemente elementi per espandere la lista o per fare le operazioni,ricreavo una lista nuova e poi la sostituivo a quella precedente.
    L' esercizio più difficile chiedeva di cancellare i valori uguali a num in modo da modificare la lista e liberare le aree di memoria,però non sapendo come fare mi sono dovuto inventare un trucchetto:
    codice:
    //Lo scopo è cancellare gli elementi che hanno il valore uguale a num. 
    void add (elem *lista, int num)
    {
        int i=0,size=0;
        elem *copia,*new;
        while(lista[i].next!=NULL)
        {
            if(lista[i].valore!=num)
            {
                size++;
                if(size==1)
                    new=(elem*)malloc(sizeof(elem));
                else
                    new=(elem*)realloc(new,size*sizeof(elem));
                new[size-1].valore=lista[i].valore;
            }
           //facevo il solito controllo per vedere se non ritorna NULL
            i++;
        }
        for(i=0;i<num-1;i++)
        {
            new[i].next=&new[i+1];
        }
        copia=lista;
        lista=new;
        free(copia);
    }
    Ho provato a fare così,è corretto?
    Ho giocato in trasferta perchè non era il mio metodo.

    A proposito del vecchio codice: sono poi riuscito a farlo partire facendo come ha detto YuYevon,poi infatti all' esame quando c'erano liste con nomi e cognomi definivo MAX_LENGHT e la tiravo su con fgets,grazie mille del consiglio

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 © 2025 vBulletin Solutions, Inc. All rights reserved.