Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11
  1. #1

    [C] Allocazione dinamica memoria per stringhe lette da file

    Buongiorno a tutti,

    Nel caso in cui abbia bisogno di leggere da file una stringa che porrò in un array? Ovviamente a priori non so quanto sarà lunga la stringa, dunque serve malloc perchè non so quanto sarà grande l'array.

    Il file ha una struttura del genere:

    -2.5 nome1 nome2
    -3 nome1 nome2
    1.3 nome1 nome2

    Se dichiaro un array statico il tutto è molto semplice:

    codice:
    struct tipo_dato
    {
           float dati.temp;
           char dati.nome1[50];
           char dati.nome2[50];
    }
    struct tipo_dato dati[365];
    
    while (!(feof(f)))
    {
            fscanf(f, "%lf %s %s", &dati.temp, dati.nome1, dati.nome2);
    }
    Ma come faccio una corretta malloc su questa struttura? Non solo non conosco la lunghezza delle stringhe nome1 e nome2 ma non so quanti record di dati immagazzinerò...ho ipotizzato rispettivamente 50, 50 e 365 (essendo dati riferiti ai giorni dell'anno).

    Come mi è stato suggerito da torn24, mi verrebbe da provare qualcosa tipo:

    codice:
    char *nome1;
    char *nome2;
    
    struct tipo_dato
    {
           float dati.temp;
           char dati.nome1[50];
           char dati.nome2[50];
    }
    struct tipo_dato *dati;
    Ma poi come sarà il codice con malloc e la fscanf?
    Chiedessi all'utente quanto sarà grande la stringa (dim), farei:
    nome1=(char *)malloc(sizeof(char)*dim);
    Ma qui ho stringhe lette da file, non so quant'è dim.
    Una cosa del genere secondo me non va bene..
    nome1=(char *) malloc(sizeof(char) * (strlen(fscanf(f,"%s %s", &nome1,)));

    Aggiungo che, una volta conosciute le stringhe nome1 e nome2, avranno poi sempre la stessa lunghezza per l'intero file letto. A quel punto ciò che non so è quanti record ha il file e quindi quante righe ha la matrice *dati.

    Grazie mille per l'aiuto.

  2. #2
    Utente di HTML.it L'avatar di torn24
    Registrato dal
    Aug 2008
    Messaggi
    551

    ciao

    Ciao, per tua utilità ti dico che non sono un programmatore ma uno a cui piace scrivere tre righe di codice per puro diletto

    intanto se dovrai aumentare di volta in volta la dimensione di un puntatore, non userai la malloc, ma la realloc.

    secondo punto, il tuo scopo è risparmiare memoria anche sui campi nome della struct, di conseguenza dovranno essere puntatori allocati dinamicamente.

    come accennato in precedenza, non sono un professionista che vorrebbe farti fare un percorso per cui tu arriveresti da solo alla soluzione, io ho sempre imparato da esempi di codice e quindi ti offro un esempio non completo, in modo che tu possa lavorarci sopra.

    codice:
     struct tipo_dato
        {
            float f;
            char *nome1; //nome1 e nome2 sono puntatori, per poterli utilizzare occorre 
                               // allocare memoria necessaria 
            char *nome2;
        };
        struct tipo_dato *dati=NULL;  //importante che il puntatore sia inizializzato a NULL
                                                 // perché la relloc() in presenza di un puntatore NULL
                                                 // si comporta come la malloc()
                                                 
    
        ........
        .......
        ......
        .......
    
        while(!feof(f))
        {
           if(feof(f))break;
           i++;
           /* occorra dichiarare nel programma la variabile contatore i
              che conta le righe lette e quindi il numero di record necessari
              e gli array di char stringa1 e stringa2, di dimensioni adeguare 
              come contenitori temporanei */
           //alloca spazio per un record  "i = numero record" a puntantore nullo si comporta come malloc
           dati=(struct tipo_dato*)realloc(dati,sizeof(struct tipo_dato)*i);
           if(dati==NULL)printf("errore");
           fscanf(f, "%f %s %s", &dati[i-1].f, stringa1, stringa2); // acquisisce i dati da file
           printf("%f %s %s\n", dati[i-1].f, stringa1, stringa2);
    
            /* 
               prima di utilizzare i campi nome, occorre allocare memoria sufficiente 
               lunghezza stringa +1, carattere terminatore */
           dati[i-1].nome1=(char*)malloc(sizeof(char)*(strlen(stringa1)+1));
           dati[i-1].nome2=(char*)malloc(sizeof(char)*(strlen(stringa2)+1));
           //copio i dati nei puntatori allocati ...
           strcpy(dati[i-1].nome1,stringa1);
           strcpy(dati[i-1].nome2,stringa2);
    
    
        }
    Tecnologia

  3. #3
    In primo luogo, è opportuno rispettare una sintassi meno emetica nella dichiarazione delle struct, perché quella proposta è davvero inguardabile. Ecco un esempio assai più felice e professionale:

    codice:
    typedef struct {
        float temp;
        char *nome1;
        char *nome2;
    } dato_t;
    ...
    dato_t mieidati[365];

    Oppure, per amor di sintesi (se non sono necessari nel codice altri riferimenti alla struct in oggetto):
    codice:
    struct {
        float temp;
        char *nome1;
        char *nome2;
    } mieidati[365];
    In secondo luogo, l'uso di realloc() è fortissimamente deprecato poiché si tratta della funzione di gran lunga più inefficiente di tutta la standard library, assieme alle degne compagne fscanf() e fprintf().
    Il suo impiego va scoraggiato in qualsiasi fase e a qualsiasi livello di preparazione.

    L'idioma più razionale per la gestione di stringhe di dimensione non prefissata, lette da file dati, consiste nell'usare uno o più buffer statici di dimensione esorbitante rispetto al caso peggiore previsto dalla specifica (o rilevato statisticamente, in mancanza di meglio), usato/i per la lettura del singolo dato da file. Il contenuto di tale buffer sarà poi, di volta in volta, copiato (con una bella strncpy()) nel buffer allocato dinamicamente, al quale punterà il relativo puntatore previsto all'interno della struttura dati. Questo approccio, peraltro, in genere impedisce l'uso dell'orrida e deprecata fscanf() (che comunque non va mai usata! Si legge l'intera riga e si usa sscanf(), semmai), in luogo di funzioni più efficienti e meno error-prone per la lettura di campi da file CDF o simili.

    Causa mancanza di tempo e forzato uso di uno smartphone, non fornisco esempi di codice, anche per stimolare una crescita didattica nell'OP.
    Ultima modifica di M.A.W. 1968; 31-12-2014 a 16:17
    • Un plauso a Grisha Perelman, raro esempio di genuino anticonformismo umano e scientifico.

  4. #4
    Quote Originariamente inviata da M.A.W. 1968 Visualizza il messaggio
    In primo luogo, è opportuno rispettare una sintassi meno emetica nella dichiarazione delle struct, perché quella proposta è davvero inguardabile. Ecco un esempio assai più felice e professionale:

    codice:
    typedef struct {
        float temp;
        char *nome1;
        char *nome2;
    } dato_t;
    ...
    dato_t mieidati[365];

    Oppure, per amor di sintesi (se non sono necessari nel codice altri riferimenti alla struct in oggetto):
    codice:
    struct {
        float temp;
        char *nome1;
        char *nome2;
    } mieidati[365];
    In secondo luogo, l'uso di realloc() è fortissimamente deprecato poiché si tratta della funzione di gran lunga più inefficiente di tutta la standard library, assieme alle degne compagne fscanf() e fprintf().
    Il suo impiego va scoraggiato in qualsiasi fase e a qualsiasi livello di preparazione.

    L'idioma più razionale per la gestione di stringhe di dimensione non prefissata, lette da file dati, consiste nell'usare uno o più buffer statici di dimensione esorbitante rispetto al caso peggiore previsto dalla specifica (o rilevato statisticamente, in mancanza di meglio), usato/i per la lettura del singolo dato da file. Il contenuto di tale buffer sarà poi, di volta in volta, copiato (con una bella strncpy()) nel buffer allocato dinamicamente, al quale punterà il relativo puntatore previsto all'interno della struttura dati. Questo approccio, peraltro, in genere impedisce l'uso dell'orrida e deprecata fscanf() (che comunque non va mai usata! Si legge l'intera riga e si usa sscanf(), semmai), in luogo di funzioni più efficienti e meno error-prone per la lettura di campi da file CDF o simili.

    Causa mancanza di tempo e forzato uso di uno smartphone, non fornisco esempi di codice, anche per stimolare una crescita didattica nell'OP.

    Vi ringrazio per le vostre risposte. Proverò a smanettare, anch'io non sono un programmatore professionista ma mi diletto.
    Intuivo che la realloc non è efficiente e infatti il codice che ho già realizzato utilizza quello stratagemma dei buffer statici spropositati ma alla fine più efficienti. Purtroppo però è un "compito per le vacanze" per l'esame di informatica A, quindi credo che sia fortemente consigliata la gestione dinamica della memoria..
    Provo a implementare la soluzione di torn24 e vedo cosa succede.

    grazie molte

  5. #5
    Quote Originariamente inviata da rosencrruetz Visualizza il messaggio
    Purtroppo però è un "compito per le vacanze" per l'esame di informatica A, quindi credo che sia fortemente consigliata la gestione dinamica della memoria..
    Dipende esclusivamente da cosa ha in mente il/la titolare del corso - e come recita un noto proverbio "Chi domanda non fa errore". Il "ricevimento", anche via email, serve appunto ad appianare simili dubbi.
    • Un plauso a Grisha Perelman, raro esempio di genuino anticonformismo umano e scientifico.

  6. #6
    Posto il mio codice (che non gira ma il compilatore non da alcun errore).
    Premetto che i file da leggere sono 2 e si deve scrivere in un terzo.
    I due file hanno un'intestazione diversa (le due stringhe di cui parlavo in precedenza) poi hanno sempre la stessa struttura ovvero:
    intestazione
    temp data
    temp data

    Devo fare la parte terminale dell'algoritmo merge-sort, quindi il sort. Scrivere nel file finale ordinando per data e qualora la data sia uguale scrivo prima il dato con temperatura minore.
    So benissimo che non sono un informatico, che non conosco bene l'allocazione dinamica e che ci saranno un'infinità di idiozie... (sebbene il programma diciamo in allocazione statica opportunamente modificato giri).

    Neanche a me piace la fscanf ma come fare la sscanf da file? se scrivo sscanf(f, "%s", stringa) il compilatore non accetta come primo argomento di sscanf un puntatore a file...

    codice:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stddef.h>
    #include <malloc.h>
    int main()
    {
    int risultato_confronto; //variabile per risultato del confronto delle date
    int i=0, j=0, k=0, l=0, m=0, cont=0, cont2=0, app1=0, app2=0;      //contatori ausiliari
    char nome1[20];
    char nome2[20];
    char nome3[20];
    char nome4[20];
    int gg1, mm1, aa1, gg2, mm2, aa2;
    struct tipo_dato            //creo struttura per immagazzinare i dati
    {
        double temp;
        char data[10];
    };
    struct tipo_dato *centrale1;    //dichiaro struttura centrale1 per Dati1.txt
    struct tipo_dato *centrale2;     //dichiaro struttura centrale2 per Dati2.txt
    FILE* f= NULL;      //puntatore al primo file
    FILE* f2 = NULL;    //puntatore al secondo file
    FILE* f3 = NULL;    //puntatore al terzo file
    f=fopen("Dati1.txt","r");
    f2=fopen("Dati2.txt","r");
    if (f==NULL || f2==NULL)
    {
        printf ("Errore nell'apertura dei file di origine.");
    }
    else
    {
        fscanf(f,"%s %s", nome1, nome2);            //leggo nome della 1a centralina dall'intestazione di Dati1.txt
        fscanf(f2,"%s %s", nome3, nome4);           //leggo nome della 2a centralina dall'intestazione di Dati2.txt
        while (!(feof(f)))
        {                       //ciclo while per lettura dati1.txt e immagazzino dati in centrale1 con reallocazione elemento per elemento
            l++;
            centrale1=(struct tipo_dato*)realloc(centrale1,sizeof(struct tipo_dato)*l);
           fscanf(f,"%lf %s", &centrale1[l-1].temp, centrale1[l-1].data);
        }
        fclose(f);
        while (!(feof(f2)))
        {                       //ciclo while per lettura dati2.txt e immagazzino dati in centrale2 con reallocazione elemento per elemento
            m++;
            centrale2=(struct tipo_dato*)realloc(centrale2,sizeof(struct tipo_dato)*m);
            fscanf(f2,"%lf %s", &centrale2[m-1].temp, centrale2[m-1].data);
        }
        fclose(f2);                         //potrei anche usare rewind(f) e rewind(f2)
        f=fopen("Dati1.txt","r");
        f2=fopen("Dati2.txt","r");
        f3=fopen("Dati.txt","w");
        i=0;
        j=0;
            while ((i<l-1)&&(j<m-1))        //conoscendo gia' quanti record hanno i due file: ciclo finche' uno dei due non termina
            {
                sscanf(centrale1[i].data, "%d/%d/%d", &gg1, &mm1, &aa1);        //leggo la data di dati1.txt
                sscanf(centrale2[j].data, "%d/%d/%d", &gg2, &mm2, &aa2);        //leggo la data di dati2.txt
                if ((aa1>aa2)||((aa1==aa2)&&(mm1>mm2))||((aa1==aa2)&&(mm1==mm2)&&(gg1>gg2)))
                    risultato_confronto=1;          //se data1>data2
                else
                {
                    if ((aa1==aa2)&&(mm1==mm2)&&(gg1==gg2))
                        risultato_confronto=0;          //se date uguali
                    else
                        risultato_confronto=-1;         //negli altri casi data1<data2
                }
                if (risultato_confronto==0)     //se data uguale
                {
                    if (centrale1[i].temp>=centrale2[j].temp)       //scrivi prima le info del record con temperatura minore
                    {
                        fprintf(f3,"%lf %s %s %s\n", centrale2[j].temp, centrale2[j].data, nome3, nome4);
                        j++;        //vai avanti con il prossimo record in dati2.txt
                        k++;
                    }
                    else            //altrimenti se data uguale e temp1<temp2 stampa le informazioni di dati1.txt
                    {
                        fprintf(f3,"%lf %s %s %s\n", centrale1[i].temp, centrale1[i].data, nome1, nome2);
                        i++;          //vai avanti con il prossimo record in dati1.txt
                        k++;
                    }
                }
                else
                {
                    if (risultato_confronto>0)      //se data1>data2 stampa le informazioni di dati2.txt
                    {
                        fprintf(f3,"%lf %s %s %s\n", centrale2[j].temp, centrale2[j].data, nome3, nome4);
                        j++;        //vai avanti con il prossimo record in dati2.txt
                        k++;
                    }
                    else            //se data1<data2 stampa le informazioni di dati1.txt
                    {
                        fprintf(f3,"%lf %s %s %s\n", centrale1[i].temp, centrale1[i].data, nome1, nome2);
                        i++;        //vai avanti con il prossimo record in dati1.txt
                        k++;
                    }
                }
            }
            if (i<l-1)      //se uno dei due file e' terminato, stampa i record dell'altro
            {
                app1=l-i;
                for (cont=0;cont<app1-1;cont++)
                {
                    fprintf(f3, "%lf %s %s %s\n", centrale1[i].temp, centrale1[i].data, nome1, nome2);
                    i++;
                    k++;
                }
            }
            if (j<m-1)      //se uno dei due file e' terminato, stampa i record dell'altro
            {
                app2=m-j;
                for (cont2=0;cont2<app2-1;cont2++)
                {
                    fprintf(f3, "%lf %s %s %s\n", centrale2[j].temp, centrale2[j].data, nome3, nome4);
                    j++;
                    k++;
                }
            }
        fclose(f2);
        fclose(f);
        fclose(f3);
    }
    return 0;
    }

  7. #7
    Utente di HTML.it L'avatar di torn24
    Registrato dal
    Aug 2008
    Messaggi
    551

    Ciao

    Neanche a me piace la fscanf ma come fare la sscanf da file? se scrivo sscanf(f, "%s", stringa) il compilatore non accetta come primo argomento di sscanf un puntatore a file...

    A me piacciono tutte, non ho molte pretese, forse perché i mie programmini non devono svolgere compiti critici, spesso la loro vita è breve, scrittura, compilazione, "funziona" morte

    forse, ti è stato suggerito, di non usare la fscanf(), ma usare la fgets(), e sulla stringa acquisita usare la sscanf();


    ho notato, che non inizializzi i puntatori dati a NULL, non dargli un valore non significa che siano NULL, ma indefiniti, e la realloc() non funziona correttamente.

    codice:
    struct tipo_dato *centrale1;
    struct tipo_dato *centrale2;
    Tecnologia

  8. #8
    Esatto, l'errore era proprio l'inizializzazione del puntatore.

    Per quanto riguarda il discorso sscanf/fgets?:

    codice:
    char buffer[100];
    int dim=0;
    char *nome1=NULL;
    ...
    fgets(buffer,100,f);         
        dim=strlen(buffer);
        nome1=(char*)malloc(nome1,sizeof(char)*(dim));
        nome1=sscanf(buffer,"%s", nome1);

    mi da errore: passing argument 1 of malloc makes integer from pointer without cast

  9. #9
    Utente di HTML.it L'avatar di torn24
    Registrato dal
    Aug 2008
    Messaggi
    551
    malloc() accetta un unico argomento, il numero di byte da allocare...

    fgets, e sscanf, è un sistema per evitare l'uso di fscanf()

    codice:
    fscanf(f,"%s %s", nome1, nome2);
    
    -----------------------------------
    fgets(buffer,100,f);
    sscanf(buffer,"%s %s", nome1, nome2);
    consiglio, invece di terminare oggi l'esercizio, aspetta qualche giorno, qualcuno ti potrebbe postare un esempio o un consiglio per ottenere risultati migliori.
    io termino qui il mio contributo, sperando di essere stato utile e non di aver creato danno
    Tecnologia

  10. #10
    Ho quasi risolto così:

    fgets(buffer,100,f); //leggo nome della 1a centralina dall'intestazione di Dati1.txt
    printf("%s\n",buffer);
    dim=strlen(buffer);
    printf("lung buffer %d\n",dim);
    nome1=(char*)malloc(sizeof(char)*dim);
    strncpy(nome1,buffer,dim);
    dim=strlen(nome1);
    printf("%d %s\n",dim, nome1);
    fgets(buffer,100,f2);
    dim=strlen(buffer);
    nome2=(char*)malloc(sizeof(char)*(strlen(buffer))) ;
    strncpy(nome2,buffer,dim);

    solo che dopo la strncopy mi stampa la stringa corretta e subito dopo dei caratteri strani :S e la dimensione passa da 23 a 30. Se nella strncpy metto al posto di nome1 *nome1 crash ugualmente..Non vorrei che quei caratteri strani siano l'indirizzo fisico boh

    Ps. in mezzo ci sono printf per debuggare..
    Ultima modifica di rosencrruetz; 31-12-2014 a 19:10

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.