Giudizio per Rubrica su file

di il
21 risposte

Giudizio per Rubrica su file

Ciao a tutti!

allora, sono arrivato finalmente alla lettura e scrittura su file e ho provato a realizzare una rubrica telefonica in C.
rubrica che salva su un file di testo l'elenco di nome, cognome e telefono.
il programma ha l'opzione di inserire, cancellare, modificare e stampare l'elenco completo
il tutto salvando il file pulito, senza righe vuote insomma...

il codice è lunghetto, quindi mi farebbe piacere se qualcuno dei master volesse dare un'occhiata al codice (lo invierei in privato) e mi desse un giudizio spassionato.

sto imparando c come autodidatta da meno di 4 mesi e vorrei capire a che punto sono arrivato!!


attendo il vostro aiuto!!

21 Risposte

  • Re: Giudizio per Rubrica su file

    Non mettere tutto il codice. Ci basta la struttura dati e il load/save da/su file. Il resto è gestione interfaccia utente presumo.
  • Re: Giudizio per Rubrica su file

    No, in realtà gira tutto su xcode, non ho fatto interfaccia... non ci sono ancora arrivato
  • Re: Giudizio per Rubrica su file

    Interfaccia utente è anche console non per forza con le finestre di dialogo o altro. Il menù che presenti per esempio non serve per dare un giudizio.
  • Re: Giudizio per Rubrica su file

    Ah ok
    allora metto il codice qui...
    attendo dei giudizi!! e sopratutto dei consigli su cosa approfondire i miei studi...
    #include <stdio.h>
    #include <string.h>
    
    struct dati {                                               //STRUTTURA DATI RUBRICA
        char nome[20]; 
        char cognome[20];                                       
        char telefono[12];
    };
    
    void insert (struct dati array[], FILE *f);                 //FUNZIONE INSERIMENTO
    void insert (struct dati array[], FILE *f){
        char contatto[60];
        long l;
        printf("Inserisci nome e cognome ");                    //inserimento dati
        scanf("%s",&array[0].nome);
        scanf("%s",&array[0].cognome);
        printf("Inserisci il telefono ");
        scanf("%s",&array[0].telefono);
    
        strcat(contatto,array->nome);                           //unisco le stringhe in un unico array
        strcat(contatto," ");                                   //mettendo uno spazio tra nome
        strcat(contatto,array->cognome);                        //cognome
        strcat(contatto," ");                                   //e telefono
        strcat(contatto,array->telefono);                       //poi vado a capo, così il file di testo riporta
        strcat(contatto,"\n");                                  //una riga per ogni nome
    
        l=strlen(contatto);                                     //controllo lunghezza della stringa con i dati
        
        printf("%s",contatto);                                  //la stampo per controllo
        fwrite(contatto,sizeof(char),l,f);                      //copio la stringa sul file rubrica.txt
        printf("Contatto inserito\n");
        strcpy(contatto,"");                                    //cancello la stringa temporanea
    }
    
    int delete (FILE *f);                                       //FUNZIONE ELIMINA
    int delete (FILE *f){
        char contatti [256][60];
        int i,c,j;
        i=0;
        c=0;
        
    
        while((fgets(contatti[i], 60, f))!=NULL) {                  //leggo dal file i contatti (finchè ne trovo) e li
            printf("%d) %s",i+1,contatti[i]);                       //copio in una matrice di 256 posizioni da 60 celle
            i++;                                                    
        }                                                           //conservo i come contatore ultima posizione
        
        printf("\nNumero contatto da cancellare? ");    //scelgo il numero relativo al contatto da eliminare
        scanf("%d",&c);                                             //lo assegno a c e poi copio nella posizione c-1
        strcpy(contatti[c-1],"?\n");                                //un carattere qualsiasi di confronto
        
        fclose(f);                                                  //chiudo il file perchè lo devo riaprire
                                                                    //in scrittura w+ (sovrascrive tutto)
        
        if ((f = fopen( "/Users/toti/Library/Developer/Xcode/files/rubrica.txt", "w+" )) == NULL ){
            return 1;                                               //controllo che la riapertura in w+ sia avvenuta
        }
        for (j=0;j<i;j++){                                          //in un ciclo da 0 a i controllo quale riga 
            if (strcmp(contatti[j],"?\n")!=0){                      //della matrice è diversa dal carattere di confronto
                fwrite(contatti[j],sizeof(char),strlen(contatti[j]),f);//e in quel caso la copio sul file riaperto
            }
        }    
        fclose(f);                                                  //chiudo il file perchè lo riaprirò in a+
        
        if ((f = fopen( "/Users/toti/Library/Developer/Xcode/files/rubrica.txt", "a+" )) == NULL ){
            return 1;                                               //controllo che la riapertura in a+ sia avvenuta
        }                                                           //verrà poi chiuso nel main al termine
        return 0;                                                   //del programma
    }
    
    int modify (FILE *f, struct dati array[]);                  //FUNZIONE MODIFICA
    int modify (FILE *f, struct dati array[]){
        char contatti [256][60];
        char contatto [60];
        int i,c,j;
        i=0;
        c=0;
        
        while((fgets(contatti[i], 60, f))!=NULL) {                  //leggo dal file i contatti (finchè ne trovo) e li
            printf("%d) %s",i+1,contatti[i]);                       //copio in una matrice di 256 posizioni da 60 celle
            i++;                                                    
        }                                                           //conservo i come contatore ultima posizione
        
        printf("\nNumero contatto da modificare? ");                //scelgo il numero relativo al contatto da eliminare
        scanf("%d",&c);                                             //lo assegno a c e poi copio nella posizione c-1
        strcpy(contatti[c-1]," ");                                  //uno spazio per cancellare tutto il contenuto
        printf("\nRiscrivi nome e cognome ");
        scanf("%s",&array[0].nome);                                 //reinserisco i dati da modificare
        scanf("%s",&array[0].cognome);
        printf("Inserisci il telefono ");
        scanf("%s",&array[0].telefono);
        
        strcat(contatto,array->nome);                           //unisco le stringhe in un unico array
        strcat(contatto," ");                                   //mettendo uno spazio tra nome
        strcat(contatto,array->cognome);                        //cognome
        strcat(contatto," ");                                   //e telefono
        strcat(contatto,array->telefono);                       //poi vado a capo, così il file di testo riporta
        strcat(contatto,"\n");
        strcpy(contatti[c-1],contatto);                         //copio nella matrice il contatto aggiornato
    
        fclose(f);                                              //chiudo e riapro in riscrittura (w+)
        if ((f = fopen( "/Users/toti/Library/Developer/Xcode/files/rubrica.txt", "w+" )) == NULL ){
            return 1;                                               //controllo che la riapertura in w+ sia avvenuta
        }
        
        for (j=0;j<i;j++){
        fwrite(contatti[j],sizeof(char),strlen(contatti[j]),f);         //copio tutta la matrice sul file rubrica.txt
        }
        printf("Contatto modificato\n");                                
        strcpy(contatto,"");                                            //cancello contenuto del array temporaneo
        return 0;
    }
    
    void print (FILE *f);                                       //FUNZIONE STAMPA
    void print (FILE *f){
        char contatti [60];                                     //array temporaneo
        int i;
        i=0;
    
        while((fgets(contatti, 60, f))!=NULL) {                  //leggo dal file i contatti (finchè ne trovo) e li
            printf("%d) %s",i+1,contatti);                       //copio nell'array temporaneo e stampo
            i++;                                                    
        }
        printf("\n");
    }
    
        int main (void)                                         //PROGRAMMA RUBRICA
    {
        FILE *f;
        int scelta;
        struct dati elenco[2];
        if ((f = fopen( "/Users/toti/Library/Developer/Xcode/files/rubrica.txt", "a+" )) == NULL ){
        return 1;
        }
        
        printf("RUBRICA TELEFONICA\n");
        
        while (scelta!=5){
        
            printf("\nMenù:\n1)Inserisci Contatto\n2)Elimina Contatto\n3)Modifica Contatto\n4)Stampa Rubrica\n5)Esci\n");
            printf("Scelta: ");
            scanf("%d",&scelta);
            
            if (scelta==1){
                insert(elenco,f);
                fseek(f,1,SEEK_END);
            }
            
            if (scelta==2){
                rewind(f);
                delete(f);
            }
            
            if (scelta==3){
                rewind(f);
                modify(f,elenco);
            }
            
            if (scelta==4){
                rewind(f);
                print(f);
            }
            
            if (scelta==5){
                printf("Chiusura programma in corso...");
                fclose(f);
                printf("\nTerminato");
            }
            
        }
    
    }
  • Re: Giudizio per Rubrica su file

    Meglio se utilizzi dei #define e non costanti numeriche: migliori in flessibilità e leggibilità.
    
    #define MAX_LEN_NOME 20
    #define MAX_LEN_COGNOME 20
    #define MAX_LEN_PHONE 12
    
    struct dati {                                               //STRUTTURA DATI RUBRICA
        char nome[MAX_LEN_NOME];
        char cognome[MAX_LEN_COGNOME];                                       
        char telefono[MAX_LEN_PHONE];
    };
    
    e analogamente tutte le altre costanti numeriche nel resto del codice. In questo modo hai un solo punto dove cambiare i valori e non corri il rischio di dimenticarne qualcuno in giro.
  • Re: Giudizio per Rubrica su file

    Effettivamente si, grazie del consiglio!
  • Re: Giudizio per Rubrica su file

    Puoi spiegare il perché di questa scelta?
    
    struct dati elenco[2];
    
    Mi sarei aspettato un array dinamico e la scrittura su file al termine del programma.
    
    void insert (struct dati array[], FILE *f){
    	char contatto[60];
    
    strcat su un'array non inizializzato causa buffer overflow. Nessuno ti assicura che l'array contatto sia inizilizzato e quindi il programma va in crash.
    Meglio inizializzare
    
    char contatto[60] = {0};
    
    oppure guarda l'esempio su questo sito
    http://www.cplusplus.com/reference/clibrary/cstring/strcat/
    Come vedi la prima chiamata è strcpy la quale appende il terminatore di stringa per la successiva chiamata.
  • Re: Giudizio per Rubrica su file

    È una scelta di ripiego perché non mi spiegavo il motivo di un errore
    che in fase di compilazione avevo risolto creando l'array...
    in realtà ora l'ho risolto, passando alle funzioni insert e modify non un array di strutture ma una struttura e modificando nello strcat da array->nome in array.nome
    diciamo che l'avevo lasciato da parte per impegnarmi sul resto del programma, mea culpa!
    invece per quanto riguarda l'allocazione dinamica della memoria, l'ho presa in considerazione, anche se non sono ancora espertissimo. e proprio perché non sono espertissimo ho preferito andare avanti nel modo più semplice... non mi sentivo pronto ad affrontarla in questo progetto...
    Per la scrittura alla fine del file: ho fatto queste aperture e chiusure all'interno del programma perché in alcuni casi ho aperto in modalità sovrascrittura (w+) ed in altre in modalità aggiunta (a+) ...passatemi il termine forse non precisissimo...
    probabilmente avrei potuto spostarmi con il cursore all'interno del file modificando la riga corrispondente al contatto da cancellare o modificare, ma non sapevo come ad esempio cancellare tutta una riga del file e accorpare tutti i contatti per continuare ad ottenere un file "pulito"...
    diciamo che ho cercato di ottenere il risultato che mi ero preposto con i mezzi di conoscenza che avevo a disposizione...
  • Re: Giudizio per Rubrica su file

    skynet ha scritto:


    strcat su un'array non inizializzato causa buffer overflow. Nessuno ti assicura che l'array contatto sia inizilizzato e quindi il programma va in crash.
    Meglio inizializzare
    
    char contatto[60] = {0};
    
    oppure guarda l'esempio su questo sito
    http://www.cplusplus.com/reference/clibrary/cstring/strcat/
    Come vedi la prima chiamata è strcpy la quale appende il terminatore di stringa per la successiva chiamata.
    chiarissimo! il mondo della programmazione è immenso!!
  • Re: Giudizio per Rubrica su file

    Controlla anche scelta. Anche lì c'è da inizializzare. Metti che all'inizio contenga 5, il while non viene eseguito. Vogliamo migliorarlo? Se non vuoi utilizzare l'allocazione dinamica perche troppo presto usiamo l'array statico delle strutture. Basta porre un limite di grandezza, diciamo non + di 100 contatti. Quindi il tuo array sarà
    
    #define MAX_ELEMENTI 100
    ......
    struct dati elenco[MAX_ELEMENTI];
    int indiciUsati[MAX_ELEMENTI];
    int indiceCorrente = 0;
    
    Adesso puoi all'inizio del programma caricare da file il tuo elenco per modifche successive e poi alla fine salvi su file tutti gli indici usati.
  • Re: Giudizio per Rubrica su file

    Ma quindi per capire, mi consigli di aprire il file, lavorarlo sempre dentro degli array in tutto il programma e solo in fase di chiusura, sovrascriverlo di tutti i dati?
  • Re: Giudizio per Rubrica su file

    Secondo me è meglio. non devi riavvolgere e posizionarti ogni volta sul file. Poi scegli tu.
  • Re: Giudizio per Rubrica su file

    Certo, effettivamente più apro e chiudo il file più possibilità di errore ci sono... quindi effettivamente è meglio...
    un giudizio complessivo per l'opera? contando che programmo da autodidatta (e con il vostro aiuto) da circa 4 mesi??
    niente buonismo, vorrei davvero capire a che punto sono...
  • Re: Giudizio per Rubrica su file

    Le indicazioni da parte mia sono:
    1. Sempre inizializzare i dati
    2. Per ogni funzione custom che si cerca di creare, cerca prima se esiste una funzione già fatta.
    3. Non complicare il problema inutilmente. La scelta di concattenare i dati la trovo errata.
    4. I file possono essere aperti anche in binario e puoi salvare una struttura intera in un solo colpo e non stringa x stringa.
    In linea di massima va bene ma cerca di non complicare il problema di più di quel che è.
    Ho fatto un esempio di lettura/scrittura file giusto per farti capire meglio. E' ancora da finire e se ci sono errori mi scuso ma non l'ho provato.
    
    #include <stdio.h>
    #include <string.h>
    
    #define MAX_ELEMENTI 100
    
    #define MAX_LEN_NOME 20
    #define MAX_LEN_COGNOME 20
    #define MAX_LEN_PHONE 12
    
    struct dati {                                               //STRUTTURA DATI RUBRICA
        char nome[MAX_LEN_NOME];
        char cognome[MAX_LEN_COGNOME];                                       
        char telefono[MAX_LEN_PHONE];
    };
    
    struct _rubrica
    {
    	struct dati elenco[MAX_ELEMENTI];
    	int indiciUsati[MAX_ELEMENTI];
    	int indiceCorrente;
    };
    
    //Legge da file e salva in rubrica, ritorna il numero di elementi letti
    int LeggiFile(FILE * f, struct _rubrica *rubrica)
    {
    	while(!feof(f))
    	{
    		if(fread(&(rubrica->elenco[rubrica->indiceCorrente]),sizeof(struct dati),1,f))
    		{
    			rubrica->indiciUsati[rubrica->indiceCorrente] = 1;
    			rubrica->indiceCorrente++;
    		}
    	}
    	return rubrica->indiceCorrente;
    }
    
    //Scrive su file leggendo da rubrica, ritorna il numero di elementi scritti
    int ScriviFile(FILE * f, struct _rubrica *rubrica)
    {
    	int i;
    	int scritti = 0;
    	for(i = 0; i < rubrica->indiceCorrente; i++)
    	{
    		if(rubrica->indiciUsati[i] == 1)
    		{
    			if(fwrite(&(rubrica->elenco[i]),sizeof(struct dati),1,f))
    				scritti++;
    		}
    	}
    	return scritti;
    }
    
    ...........
    
    int main (void)                                         //PROGRAMMA RUBRICA
    {
    	
    	struct _rubrica rubrica;
    	
    	FILE *f;
       	int i;
    	for(i = 0; i < MAX_ELEMENTI; i++)
    		rubrica.indiciUsati[i] = 0;
    	rubrica.indiceCorrente = 0;
    
    	  if ((f = fopen( "rubrica.txt", "a+b" )) == NULL ){
        return 1;
        }
    ..................
    //Devo ancora continuare
    }
    
    
    
Devi accedere o registrarti per scrivere nel forum
21 risposte