Problema con sottoprogramma (strutture e funzione fscanf)

di il
14 risposte

Problema con sottoprogramma (strutture e funzione fscanf)

Non riesco a capire perchè non funzioni questo sottopogramma: non mi lascia inserire gli input!

void inserisciannuncio (int k){
    
    FILE *fd;
    datiannuncio a[50];
    
    fd=fopen("Desktop/Programmi/BACHECA ANNUNCI/BACHECA ANNUNCI/ANNUNCI", "a");
    if( fd==NULL ) {
        perror("Errore in apertura del file");
        exit(1);
    }
    
    
    printf ("\n----------------------------------------------\n");
    
    printf ("\n\nINSERISCI I DATI DEL TUO ANNUNCIO\n\n");

    printf ("NICKNAME: ");
    fgets (a[k].nick , 20 , fd);
    fprintf (fd, "NICKNAME: %s\n", a[k].nick );
    
    printf ("NOME E COGNOME: ");
    fgets (a[k].nomecognome , 50 , fd);
    fprintf(fd, "NOME E COGNOME:%s\n", a[k].nomecognome );
    
    printf ("CONTATTO: ");
    fgets (a[k].contatto, 50 , fd);
    fprintf (fd, "CONTATTO :%s\n", a[k].contatto );
    
    printf ("DATA E ORA (gg/mm/aaaa hh/mm): ");
    fgets (a[k].dataora, 16 , fd);
    fprintf (fd, "DATA E ORA: %s\n", a[k].dataora );
    
    printf ("TITOLO: ");
    fgets (a[k].titolo, 20 , fd);
    fprintf(fd, "TITOLO: %s\n", a[k].titolo );
    
    printf ("DESCRIZIONE: ");
    fgets (a[k].descrizione , 2000 , fd);
    fprintf(fd, "DESCRIZIONE: %s\n", a[k].descrizione );
    
    fclose(fd);

}

14 Risposte

  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    "Non mi lascia inserire" che vuol dire esattamente? Errori? Problemi?

    La struttura qual è?

    Comunque hai visto che tutte le fgets si riferiscono al file fd ? Non pensi sia un errore ?
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Ho risolto usando la gets
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    polimi2015 ha scritto:


    ho risolto usando la gets
    Il che, in ultima analisi, non costituisce una "soluzione". Sarebbe stato necessario e sufficiente variare il file nelle fgets già presenti, come implicitamente sottolineato dal nostro ottimo Oregon, sostituendo all'errato "fd" il corretto "stdin", per ottenere una soluzione non solo non meno corretta, ma significativamente più robusta e affidabile del ricorso alla deprecata gets.
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Sono un principiate in C e spesso mi trovo in difficoltà perchè le soluzioni proposte sono superiori alle mie conoscenze
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Tutti i programmatori sono stati principianti. Si tratta solo di attivarsi a ricercare e chiedere ulteriori spiegazioni quando si incontra qualcosa che non si comprende, oltre a basarsi su dei buoni testi.
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Ok, ho sistemato ripristinando la fgets e usando "stdin". Ora quando nel terminale devo inserire le informazioni, il primo dato che devo inserire è nome e cognome e il nickname non me lo lascia inserire. Es:

    ###########################

    BACHECA ANNUNCI

    ###########################


    [I] - Inserire annuncio
    [V] - Visualizare annunci
    [C] - Cercare annunci

    [H] - Aiuto
    [E] - Salva ed esci
    SCELTA: I

    ----------------------------------------------


    INSERISCI I DATI DEL TUO ANNUNCIO

    NICKNAME: NOME E COGNOME: Mario Rossi
    CONTATTO:
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Il mio sottoprogramma ora è:
    void inserisciannuncio (){
        
        FILE *fd;
        datiannuncio a;
        char si_no;
        char scelta;
        
        fd=fopen("/Programmi/BACHECA ANNUNCI/BACHECA ANNUNCI/ANNUNCI", "a");
        if( fd==NULL ) {
            perror("Errore in apertura del file");
            exit(1);
        }
        
        
        printf ("\n----------------------------------------------\n");
        
        printf ("\n\nINSERISCI I DATI DEL TUO ANNUNCIO\n\n");
    
        printf ("NICKNAME: ");
        fgets (a.nick , 20 , stdin);
        
        printf ("NOME E COGNOME: ");
        fgets (a.nomecognome , 50 , stdin);
        
        printf ("CONTATTO: ");
        fgets (a.contatto , 50 , stdin );
        
        printf ("DATA E ORA (gg/mm/aaaa hh/mm): ");
        fgets (a.dataora , 16 , stdin);
        
        printf ("TITOLO: ");
        fgets (a.titolo , 50 , stdin);
        
        printf ("DESCRIZIONE: ");
        fgets (a.descrizione , 2000 , stdin);
        
        scelta = confermare (si_no);
        
    
        if (scelta=='S')
        {
            fprintf (fd, "%s\n", a.nick );
            
            fprintf (fd, "%s\n", a.nomecognome );
            
            fprintf (fd, "%s\n", a.contatto );
            
            fprintf (fd, "%s\n", a.dataora );
            
            fprintf (fd, "%s\n", a.titolo );
            
            fprintf (fd, "%s\n", a.descrizione );
            
            fclose (fd);
        }
            
        
        menuprincipale();
        
    }
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Sicuramente è il solito problema della pulizia del buffer dopo l'input della scelta della voce del menu. Cerca in questo stesso forum ne abbiamo parlato tante volte.

    Piuttosto occhio alla chiamata della funzione del menu alla fine della funzione di inserimento
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Oltre al problema evidenziato dal nostro ottimo Oregon, c'è anche un macroscopico errore di engineering.
    Il formato scelto per la memorizzazione nel file è forse adatto per un report o una presentazione su schermo, ma è del tutto inefficiente e comporta una ridondanza del tutto inutile (i nomi dei campi ripetuti per ogni record!), che inevitabilmente poi ti complicherà la vita in fase di rilettura.

    Per un file del genere, considerando anche che si tratta di un esercizio, va benissimo l'uso di ASCII ma devi assolutamente usare le convenzioni dei più semplici file delimited (CDF ossia comma-delimited file):
    1) Un record su ogni "riga", quindi si usa un solo '\n' al termine;
    2) Campi separati da un simbolo convenzionale, i più gettonati sono ',' e ';';
    3) Stringhe (campi) singolarmente delimitate da virgolette semplici o doppie (meglio).

    Peraltro, è assolutamente opportuno raggruppare tutte le fprintf() in un singolo statement a valle degli input, sia per massimizzare l'efficienza che per coerenza logica.
    
        fprintf(fd, "\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\"\n", 
                a[k].nick, 
                a[k].nomecognome,
                a[k].contatto,
                a[k].dataora,
                a[k].titolo;
                a[k].descrizione);
    
    Volendo si può anche organizzare il file per colonne a larghezza fissa, ciascuna corrispondente ad un campo, in puro stile stegosauro COBOL o simili, sempre restando al confine tra il report human-readable e la memorizzazione su file vera e propria.

    Potrebbe essere utile, inoltre, assegnare un numero strettamente sequenziale (senza andar troppo per il sottile con eventuali cancellazioni) ad ogni "annuncio", memorizzandolo ad inizio riga.
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Non sono particolarmente d'accordo sul formato di memorizzazione: l'avere il nome dei campi può avere un suo "perchè" per fare una sorta di XML dei poveri (ovvero astrarsi da numero e sequenza dei campi stessi).
    Analogamente si può pensare anche a un json "dei poveri" nel caso in cui si voglia maggior compattezza.
    Se ci si vuol orientare verso qualcosa di più semplice, lasciando stare serializzatori più o meno sofisticati a favore di primi esercizi, inizierei col memorizzare le due informazioni più utili, ovvero numero dei record e numero dei campi per record, per poi mettere il resto
    
    2
    6
    alberto
    giovanni
    ....
    Rendendo facile capire che ci sono 2 record di 6 campi (in realtà il numero di campi ti servirà come controllo di completezza dei poveri).
    Certo puoi mettere degli indicatori di inizio record, fine record, etc (o salvare direttamente un XML o magari un tablespace innodb fatto "in casa"), però il "trucchetto" di avere il numero di campi ti consentirà di fare un ciclo for invece di dover fare un while sperando che il file non sia troncato, leggendo direttamente una riga alla volta, senza bisogno di escape dei caratteri o cose del genere (a parte ovviamente CR e LF, ipotizzo di usare come terminatore di riga queste informazioni).
    Volendo puoi sempre inventarti in fase di scrittura una sostituzione di CR (LF) con token praticamente sicuri conchessò @#CR@ e poi in fase di lettura fare il contrario (sostituire tutti i token @#CR@ con la rappresentazione iniziale)

    Ovviamente puoi inventarti tutte le strutture che vuoi, ad esempio un hash finale da usare come checksum e chi più ne ha ne metta. Inizialmente però andrei di sequenza di righe, con miniheader
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Un'annotazione: evita i percorsi (perchè poi usi / invece di \, trattandosi di Win?) sottocartelle di programmi (programmi (x86) e così via), perchè potresti incappare in problemi seri di ACL e/o UAC.
    In pratica le versioni più moderne (?) di Windows non hanno molto piacere (con le impostazioni di default) che un programma scriva dentro la cartella programmi (e "cugine"), neppure per mantenerci sopra i suoi archivi.
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Ben vengano utili suggerimenti sulle varie alternative, ma purtroppo condivido con Oregon la fastidiosa sensazione che questo thread faccia facilmente presagire ulteriori notevoli difficoltà, quale che sia il formato scelto, senza troppo badare ad harcoded format vs header/datadriven.
    "Whether ’tis nobler in the mind to suffer the slings and arrows of outrageous fortune, or to take arms against a sea of troubles", temo invero che come l'irresoluto danese anche l'OP troverà qualsiasi strada parecchio ardua e perfino impraticabile, che passi prima per la Scilla di una strtok e dopo per Cariddi con rewind e fseek per aggiungere qualche utile informazione in testa al file, o altrimenti.
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Non sarei così "pessimista", basta iniziare un byte (passo) alla volta : divide et impera (il processo solutivo) è spesso valido anche per gli approcci naïf.
    Anche un viaggio di mille miglia comincia con un primo passo
  • Re: Problema con sottoprogramma (strutture e funzione fscanf)

    Come si potrebbe essere in disaccordo con Lao Tzu? Purtroppo però spesso vedo che questi ragazzi sono travolti dall'urgenza del superare l'esame, penalizzati dalla pessima qualità delle spiegazioni e spesso anche dalla mancanza di un testo di riferimento, al punto da non riuscire a cogliere sul momento utili suggerimenti che invece sarebbero pienamente alla loro portata. Donde il pessimismo cosmico (o statistico, se si preferisce).

    Comunque una giusta dose di stimoli può solo arricchire il thread, anche per altri futuri lettori (e per lo stesso OP dopo qualche tempo). Impossibile dire a priori cosa colpirà la fantasia o risulterà più "immediato" per un particolare discente su un forum, quindi ha ampiamente senso provare ad "aggredire" il problema da due o tre diverse angolazioni.
Devi accedere o registrarti per scrivere nel forum
14 risposte