C14 #11 Gestione dei file di testo, matrici e struct Piero Scotto - C14 1 Finalità del corso Finalità del corso Finalità del corso Finalità del corso Finalità del corso Piero Scotto - C14 2 Il cifrario di Cesare Si scriva un programma che cifri/decifri un file di testo in base ad un codice segreto. Il programma deve chiedere il nome del file di input, il nome del file di output e il codice segreto (un numero intero). La cifratura avviene sostituendo le sole lettere (maiuscole e minuscole separatamente) con altre lettere in base al valore del codice. Il valore del codice indica di quanti caratteri si deve traslare ciascuna delle lettere: se ad es. il codice è 3, allora ‘A’ --> ‘D’, ‘B’ --> ‘E’, ... ‘X’ --> ‘A’, ‘Y’ --> ‘B’, ‘Z’ --> ‘C’. La corrispondenza completa delle lettere maiuscole (per le minuscole è analogo) è: Ad esempio, con codice=3 “Ciao” diventa “Fldr”. Si noti che per decifrare un testo basta inserire come codice il valore opposto a quello usato per la cifratura (qui –3). Piero Scotto - C14 3 #define MAXSTRING 80 #define LETTEREALFABETO 26 int main() { int codice, i, l; int c; char riga[MAXSTRING]; /* riga da cifrare e’ un vettore di 80 caratteri */ char FileIN[FILENAME_MAX]; char FileOUT[FILENAME_MAX]; /* FILE *fpIN, *fpOUT; printf("Input file: "); gets(FileIN); if ( (fpIN = fopen(FileIN, "r")) == NULL ) { fprintf(stderr, "Impossibile aprire il file: %s\n", FileIN); return EXIT_FAILURE; } printf("Output file: "); gets(FileOUT); if ( (fpOUT = fopen(FileOUT, "w")) == NULL ) { fprintf(stderr, "Impossibile aprire il file: %s\n", FileOUT); return EXIT_FAILURE; } printf("Codice: "); scanf("%d", &codice); Piero Scotto - C14 4 #include<stdio.h> #include<ctype.h> #include<string.h> #include<stdlib.h> #define MAXSTRING 80 #define LETTEREALFABETO 26 int main() { int codice, i, l; int c; char riga[MAXSTRING]; /* riga da cifrare */ char FileIN[FILENAME_MAX]; /* FILENAME_MAX e’ la massima lunghezza di un file, costante di stdio.h */ char FileOUT[FILENAME_MAX]; FILE *fpIN, *fpOUT; /* fpIN e fpOUT sono dei puntatori ai file che leggo e che scrivo */ printf("Input file: "); gets(FileIN); if ( (fpIN = fopen(FileIN, "r")) == NULL ) { fprintf(stderr, "Impossibile aprire il file: %s\n", FileIN); return EXIT_FAILURE; } /* una possibile modalita’ di apertura del file in lettura con segnalazione di errore */ printf("Output file: "); gets(FileOUT); if ( (fpOUT = fopen(FileOUT, "w")) == NULL ) { fprintf(stderr, "Impossibile aprire il file: %s\n", FileOUT); return EXIT_FAILURE; } /* una possibile modalita’ di apertura del file in scrittura con segnalazione di errore */ printf("Codice: "); scanf("%d", &codice); Piero Scotto - C14 5 /* I valori utili per codice sono da 0 a 25, ad es. 26 equivale a 0, 27 a 1, etc. quindi conviene riportare il codice fornito dall'utente come ad un valore tra 0 e 25 calcolando il resto di (codice % 26). Lo standard pero' non garantisce che l'operatore % mantenga il segno nel risultato, quindi lo si calcola sempre come valore positivo e poi si cambia di segno al risultato se codice era negativo */ codice = (codice>=0 ? +1 : -1) * (abs(codice) % LETTEREALFABETO); while (fgets(riga, MAXSTRING, fpIN) != NULL) /* ciclo while fino alla fine del file */ { l = strlen(riga); /* misuro la lunghezza della riga, cioe’ quanti sono i caratteri */ for (i=0; i<l; i++) { c = riga[i]; /* metto il carattere i-esimo in c */ if (isupper(c)) /* maiuscola */ { c += codice; if (c > 'Z') /* sfora a destra */ c -= LETTEREALFABETO; else if (c < 'A') /* sfora a sinistra */ c += LETTEREALFABETO; riga[i] = (char)c; /* operazione di casting su c */ } else if (islower(c)) /* minuscola */ { c += codice; if (c > 'z') c -= LETTEREALFABETO; else if (c < 'a') c += LETTEREALFABETO; riga[i] = (char)c; } } fputs(riga, fpOUT); /* metto la riga modificata sul file fpOUT */ } fclose(fpIN); fclose(fpOUT); return EXIT_SUCCESS; Piero Scotto - C14 } 6 E’ opportuno mettere il file di testo nella directory di devcpp o del compilatore e ricordarsi il nome. Se mandiamo in esecuzione il file e indichiamo testo.txt ovvero “Quel ramo del lago di Como, che volge a mezzogiorno, tra due catene non interrotte di monti, tutto a seni e a golfi, a “ e testo2.txt come file di output con codice 35 otteniamo: “Zdnu ajvx mnu ujpx mr Lxvx, lqn exupn j vniixprxawx, caj mdn ljcnwn wxw rwcnaaxccn mr vxwcr, cdccx j bnwr n j pxuor, j” Se poi usiamo testo2.txt come testo di input e testo3.txt come testo di output scrivendo come codice -35 abbiamo nuovamente il testo iniziale. Piero Scotto - C14 7 Piero Scotto - C14 8 Piero Scotto - C14 9 Piero Scotto - C14 10 Piero Scotto - C14 11 Piero Scotto - C14 12 Piero Scotto - C14 13 Piero Scotto - C14 14 Piero Scotto - C14 15