Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Problema con la scrittura in file binario
Forum - C/C++ - Problema con la scrittura in file binario

Avatar
Bug_Digitale (Normal User)
Newbie


Messaggi: 3
Iscritto: 25/01/2022

Segnala al moderatore
Postato alle 21:11
Lunedì, 31/01/2022
Mi sto approcciando ora ai file e ho fatto questo esercizio:

Codice sorgente - presumibilmente C++

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4. #define max 50
  5. #define num_s 2
  6.  
  7. typedef struct{
  8.         char nome[max];
  9.         char cognome[max];
  10.         int voto;
  11. }struttura;
  12.  
  13. int main(){
  14.         struttura studente;
  15.         int i;
  16.         FILE *f;
  17.        
  18.         if((f=fopen("archivio.txt", "wb"))==NULL){
  19.                 printf("errore nell'apertura del file!");
  20.                 exit(0);
  21.         }
  22.        
  23.         for(i=0;i<num_s; i++){
  24.                 printf("Studente n %d:\n", i+1);
  25.                 printf("\nNome: ");
  26.                 scanf("%s", &studente.nome);
  27.                 printf("\nCognome: ");
  28.                 scanf("%s", &studente.cognome);
  29.                 printf("\nVoto: ");
  30.                 scanf("%d", &studente.voto);           
  31.                 fwrite(&studente, sizeof(struttura), 1, f);
  32.         }      
  33.        
  34.         fclose(f);
  35. }


dove devo semplicemente inserire i dati dello studente nel file archivio.txt . Non mi da errori di compilazioni ma mi stampa questo:

mario                  %@      !@     <       `rossi        ÿÿÿÿÿÿÿÿ<              ;)%@        
   giovanni               %@      !@     <       `verdi        ÿÿÿÿÿÿÿÿ<              ;)%@          

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 0:05
Martedì, 01/02/2022
A parte un paio di errori con scanf(), il problema del testo in uscita "pasticciato" nasce dalla differenza tra fopen() usato con attributo d'accesso testuale o binario e dall'uso di fwrite() in luogo di fprintf().

Se apri un file con accesso binario il carattere '\n' viene preso alla lettera e in windows e in macintosh non dà un vero "a capo" (in macintosh l'"a capo" è \r, mentre in windows è \r\n).

Se usi fwrite(), scrivi sul file sempre alla lettera e byte per byte TUTTO quello che c'è nello spazio di memoria puntato dal primo parametro. Siccome dichiari la struttura studente con due buffer da 50 caratteri ciascuno, ad ogni scrittura vengono scritti su file TUTTI i 100 caratteri più i byte occupati dall'intero successivo. Se in un campo da 50 char ne hai impostato solo alcuni, quelli non impostati vengono comunque scritti alla lettera con il loro contenuto casuale.

Codice sorgente - presumibilmente C++

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4.  
  5. #define max 50
  6. #define num_s 2
  7.  
  8. typedef struct{
  9.     char nome[max];
  10.     char cognome[max];
  11.     int voto;
  12. } struttura;
  13.  
  14. int main() {
  15.     struttura studente; /* qui il contenuto di studente e' indeterminato */
  16.     int i;
  17.     FILE *f;
  18.  
  19.     if((f=fopen("archivio.txt", "wb"))==NULL){
  20.         printf("errore nell'apertura del file!");
  21.         exit(0);
  22.     }
  23.  
  24.     for(i=0;i<num_s; i++){
  25.         printf("Studente n %d:\n", i+1);
  26.        
  27.         printf("\nNome: ");
  28.         scanf("%s", studente.nome); /* era scanf("%s", &studente.nome); */
  29.        
  30.         printf("\nCognome: ");
  31.         scanf("%s", studente.cognome); /* era scanf("%s", &studente.cognome); */
  32.        
  33.         printf("\nVoto: ");
  34.         scanf("%d", &studente.voto);
  35.  
  36.         fwrite(&studente, sizeof(struttura), 1, f);
  37.  
  38.         /* Con fwrite() scrivi nel file non soltanto le stringhe e i valori
  39.         ** appena immessi, ma anche tutto il contenuto ancora indeterminato
  40.         ** di parte dei campi nome e cognome se il nome e' "mario", hai
  41.         ** inserito in studente.nome sei caratteri (m,a,r,i,o,\0), ma i 44
  42.         ** successivi rimangono com'erano al momento della dichiarazione
  43.         ** della variabile struttura studente, cioe' indeterminati, e vengono
  44.         ** scritti tali e quali nel file. Per i campi successivi valgono
  45.         ** analoghe considerazioni. */
  46.  
  47.         /* Se vuoi che il file sia correttamente leggibile, usa fprintf()
  48.         ** (nota: siccome il file e' stato aperto con attributi binari e non
  49.         ** testuali, per ottenere l'a capo in windows occorre usare \r\n,
  50.         ** non solo \n) */
  51.  
  52.         /*
  53.         fprintf(f,"%s %s %d\r\n",studente.nome,studente.cognome,studente.voto);
  54.         */
  55.        
  56.         /* volendo usare solo \n come carattere di "a capo" in fprintf() avresti
  57.         ** dovuto aprire il file con attributo d'accesso "w", non "wb" */
  58.        
  59.         /*
  60.         fopen("archivio.txt", "w"); // alla riga 19
  61.         */
  62.     }
  63.  
  64.     fclose(f);
  65.    
  66.     return 0; /* il return non deve mai mancare in int main() */
  67. }


Ultima modifica effettuata da AldoBaldo il 01/02/2022 alle 0:10


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
nessuno (Normal User)
Guru^2


Messaggi: 6379
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 5:10
Martedì, 01/02/2022
A me pare che non ci siano problemi nella scrittura binaria dei dati della struttura.

Probabilmente tu non hai chiaro il significato di file e scrittura binaria. Faresti meglio a studiarli prima da un libro e poi fare esercizi.


Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti (uno dei padri fondatori del moderno Calcolo delle probabilità) chiamava il gioco del Lotto Tassa sulla stupidità.
PM Quote
Avatar
Bug_Digitale (Normal User)
Newbie


Messaggi: 3
Iscritto: 25/01/2022

Segnala al moderatore
Postato alle 17:28
Giovedì, 03/02/2022
Testo quotato

Postato originariamente da AldoBaldo:
A parte un paio di errori con scanf(), il problema del testo in uscita "pasticciato" nasce dalla differenza tra fopen() usato con attributo d'accesso testuale o binario e dall'uso di fwrite() in luogo di fprintf().

Se apri un file con accesso binario il carattere '\n' viene preso alla lettera e in windows e in macintosh non dà un vero "a capo" (in macintosh l'"a capo" è \r, mentre in windows è \r\n).

Se usi fwrite(), scrivi sul file sempre alla lettera e byte per byte TUTTO quello che c'è nello spazio di memoria puntato dal primo parametro. Siccome dichiari la struttura studente con due buffer da 50 caratteri ciascuno, ad ogni scrittura vengono scritti su file TUTTI i 100 caratteri più i byte occupati dall'intero successivo. Se in un campo da 50 char ne hai impostato solo alcuni, quelli non impostati vengono comunque scritti alla lettera con il loro contenuto casuale.

Codice sorgente - presumibilmente C++

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4.  
  5. #define max 50
  6. #define num_s 2
  7.  
  8. typedef struct{
  9.     char nome[max];
  10.     char cognome[max];
  11.     int voto;
  12. } struttura;
  13.  
  14. int main() {
  15.     struttura studente; /* qui il contenuto di studente e' indeterminato */
  16.     int i;
  17.     FILE *f;
  18.  
  19.     if((f=fopen("archivio.txt", "wb"))==NULL){
  20.         printf("errore nell'apertura del file!");
  21.         exit(0);
  22.     }
  23.  
  24.     for(i=0;i<num_s; i++){
  25.         printf("Studente n %d:\n", i+1);
  26.        
  27.         printf("\nNome: ");
  28.         scanf("%s", studente.nome); /* era scanf("%s", &studente.nome); */
  29.        
  30.         printf("\nCognome: ");
  31.         scanf("%s", studente.cognome); /* era scanf("%s", &studente.cognome); */
  32.        
  33.         printf("\nVoto: ");
  34.         scanf("%d", &studente.voto);
  35.  
  36.         fwrite(&studente, sizeof(struttura), 1, f);
  37.  
  38.         /* Con fwrite() scrivi nel file non soltanto le stringhe e i valori
  39.         ** appena immessi, ma anche tutto il contenuto ancora indeterminato
  40.         ** di parte dei campi nome e cognome se il nome e' "mario", hai
  41.         ** inserito in studente.nome sei caratteri (m,a,r,i,o,\0), ma i 44
  42.         ** successivi rimangono com'erano al momento della dichiarazione
  43.         ** della variabile struttura studente, cioe' indeterminati, e vengono
  44.         ** scritti tali e quali nel file. Per i campi successivi valgono
  45.         ** analoghe considerazioni. */
  46.  
  47.         /* Se vuoi che il file sia correttamente leggibile, usa fprintf()
  48.         ** (nota: siccome il file e' stato aperto con attributi binari e non
  49.         ** testuali, per ottenere l'a capo in windows occorre usare \r\n,
  50.         ** non solo \n) */
  51.  
  52.         /*
  53.         fprintf(f,"%s %s %d\r\n",studente.nome,studente.cognome,studente.voto);
  54.         */
  55.        
  56.         /* volendo usare solo \n come carattere di "a capo" in fprintf() avresti
  57.         ** dovuto aprire il file con attributo d'accesso "w", non "wb" */
  58.        
  59.         /*
  60.         fopen("archivio.txt", "w"); // alla riga 19
  61.         */
  62.     }
  63.  
  64.     fclose(f);
  65.    
  66.     return 0; /* il return non deve mai mancare in int main() */
  67. }





scusa ma per i file binari è possibile usare fprintf?? e grazie l'aiuto (non sapevo non si potesse usare \n ahah)

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 18:03
Giovedì, 03/02/2022
Se apri un file con modalità di accesso binaria puoi usare fprintf(), ma gli "a capo" non saranno adattati alla piattaforma.

Prova questo:

Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int main() {
  5.     FILE *f = fopen( "prova.txt", "wb" );
  6.  
  7.     if( f ) {
  8.         fprintf( f, "Hello world!\nA capo\rA capo\r\nA capo" );
  9.         fclose( f );
  10.     }
  11.  
  12.     return 0;
  13. }



Aprendo in windows con Notepad il file prova.txt, solo l'ultimo dei tre "a capo" dà luogo a un "a capo" effettivamente visibile (quello con la coppia \r\n). I caratteri \n e \r singoli, pur essendo presenti nel file, non danno luogo ad "a capo" visibili.

Altri programmi (ad esempio, WordPad e Notepad++) visualizzano come "a capo" tutti e tre i casi, ma credo siano casi particolari legati al modo in cui sono strutturati. OpenOffice Writer si comporta in modo ancora più strano, saltando a pie' pari una delle tre ripetizioni di "A capo".

Cambiando i requisiti di accesso da "wb" a "w", Notepad visualizza il primo e l'ultimo "a capo" poiché in entrambi compare \n, ma non riconosce come "a capo" il semplice \r. Da notare che Notepad++ in un eccesso di zelo considera \r\n come un DOPPIO "a capo"...

Insomma, meglio non mischiare le due cose. Se vuoi usare fprintf() conviene aprire i file con modalità di accesso testuale; se vuoi usare fwrite() conviene aprire i file con modalità di accesso binaria.

Fai un po' di prove!


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
nessuno (Normal User)
Guru^2


Messaggi: 6379
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 18:43
Giovedì, 03/02/2022
Non ha senso usare la fprintf se il file è aperto in binario. A quel punto usa un normale file aperto in modalità testo.

Il binario si usa per gestire velocemente e in maniera più compatta i dati sul file. Si usano le funzioni apposite e NON si può pensare di potere visualizzare o gestire i dati del file binario come se fossero normale testo.

Mi sa che state facendo confusione.


Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti (uno dei padri fondatori del moderno Calcolo delle probabilità) chiamava il gioco del Lotto Tassa sulla stupidità.
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 20:24
Giovedì, 03/02/2022
Appunto. Infatti ho scritto: "Insomma, meglio non mischiare le due cose. Se vuoi usare fprintf() conviene aprire i file con modalità di accesso testuale; se vuoi usare fwrite() conviene aprire i file con modalità di accesso binaria."


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
Bug_Digitale (Normal User)
Newbie


Messaggi: 3
Iscritto: 25/01/2022

Segnala al moderatore
Postato alle 23:51
Giovedì, 03/02/2022
okok, farò un po' di prove, grazie mille ad entrambi :)

PM Quote