Politecnico di Milano Esercizi Esercizi di riepilogo sul linguaggio C: file, puntatori, liste Codifica file di testo Utilizzando la codifica di Cesare, scrivere un programma in grado di criptare e decriptare un file di testo Il programma chiederà all utente il nome del file da elaborare, il nome del file in cui scrivere il risultato, l operazione da effettuare (codifica o decodifica) ed il codice. - 2-1
#include <stdio.h> #include <string.h> Codifica file di testo const unsigned int CRIPTA = 0; const unsigned int DECRIPTA = 1; void codificacesare (char *car, unsigned int k, unsigned int azione) int temp;. - 3 - Codifica file di testo if (azione == CRIPTA) *car = *car - 'a'; temp = *car + k; if (temp < 26) *car = temp; else *car = temp - 26; *car = *car + 'a';. - 4-2
Codifica file di testo else /* decripta */ *car = *car - 'a'; temp = *car - k; if (temp >= 0) *car = temp; else *car = temp + 26; *car = *car + 'a';. - 5 - Codifica file di testo void codificafile(char nfilein[], char nfileout[], unsigned int cod, unsigned int oper) FILE *filein, *fileout; char car; filein = fopen (nfilein, "r"); fileout = fopen (nfileout, "w"); fscanf (filein, "%c", &car); while (!feof(filein)) codificacesare (&car, cod, oper); fprintf (fileout, "%c", car); fscanf (filein, "%c", &car); fclose (filein); fclose (fileout);. - 6-3
Codifica file di testo void main() char nomefilein[100], nomefileout[100]; unsigned int codice, operazione; printf ("File input: "); scanf ("%s", nomefilein); printf ("File output: "); scanf ("%s", nomefileout); printf ("Codice: "); scanf ("%u", &codice); printf ("0=cripta, 1=decripta: "); scanf ("%u", &operazione); codificafile (nomefilein, nomefileout, codice, operazione);. - 7 - Elimina tag HTML Il programma legge un file di testo contenente una pagina HTML, elimina i tag presenti e salva il testo in un altro file. I tag scartati saranno visualizzati sul monitor. Miglioramenti: Scrivere solo il testo che si trova in <body> </body> Scrivere i tag in modo più leggibile: uso sotto l altro con i simboli < e > - 8-4
#include <stdio.h> Elimina tag HTML void eliminatag (char nomefilehtml[], char nomefiletesto[]) typedef enum tag, testo, errore TipoStato; FILE *dochtml, *doctesto; char car; TipoStato stato = testo; dochtml = fopen (nomefilehtml, "r"); if (dochtml == NULL) printf ("File %s non trovato\n", nomefilehtml); return; - 9 - Elimina tag HTML doctesto = fopen (nomefiletesto, "w"); fscanf (dochtml, "%c", &car); while (!feof(dochtml) && stato!= errore) if (stato == testo) switch (car) case '<': stato = tag; break; case '>': stato = errore; break; default: fprintf (doctesto, "%c", car); break; - 10-5
Elimina tag HTML else if (stato == tag) switch (car) case '<': stato = errore; break; case '>': stato = testo; break; default: printf ("%c", car); break; fscanf (dochtml, "%c", &car); fclose (doctesto); fclose (dochtml); - 11 - Elimina tag HTML void main() char nomefilehtml[255], nomefiletesto[255]; printf ("Nome file HTML: "); scanf ("%s", nomefilehtml); printf ("Nome file testo: "); scanf ("%s", nomefiletesto); eliminatag (nomefilehtml, nomefiletesto); - 12-6
Archivio film Il programma dovrà permettere all utente, tramite un menù, di gestire un archivio di film Dovranno essere disponibili le seguenti operazioni: 1. L utente inserisce un certo numero di film: Codice identificativo numerico e titolo (senza spazi) L inserimento della lista di film è terminato immettendo uno codice pari a zero 2. L utente inserisce un codice e l elaboratore verifica se il corrispondente film è presente nel file (ed in questo caso ne scrive i dati sul monitor) Utilizzare l algoritmo di ricerca binaria e l algoritmo bubble-sort E se usassimo l ordinamento per inserzione? - 13 - Archivio film: ricerca binaria Valore della variabile inizio Valore della variabile medio Valore della variabile fine 0 1 2 0 101 102 203 204 305 306 Posizione iniziale all apertura del file Posizione dopo fseek() archivio = fopen ("pippo", "rb"); fseek (archivio, -sizeof(film), SEEK_END); inizio = 0; fine = ftell(archivio) / sizeof(film); medio = (inizio + fine) / 2; - 14-7
Archivio film #include <stdio.h> typedef struct unsigned int codice; char titolo[100]; Film; void ordina (char nomefile[]) typedef enum falso, vero Booleano; FILE *archivio; Film filmcorrente, filmsuccessivo; unsigned int numfilm, i; Booleano scambio; - 15 - Archivio film /* "r+b" permette di leggere/scrivere su file binario esistente */ archivio = fopen (nomefile, "r+b"); fseek (archivio, -sizeof(film), SEEK_END); /* calcola numero di film inseriti nel file */ numfilm = ftell (archivio) / sizeof(film) + 1 ; do scambio = falso; /* si riporta a inizio file */ fseek (archivio, 0, SEEK_SET); - 16-8
Archivio film for (i = 0; i < numfilm - 1; i++) fread (&filmcorrente, sizeof(film), 1, archivio); fread (&filmsuccessivo, sizeof(film), 1, archivio); if (filmcorrente.codice > filmsuccessivo.codice) /* sposta testina due record all'indietro */ fseek(archivio,-2*sizeof(film), SEEK_CUR); fwrite (&filmsuccessivo, sizeof(film),1, archivio); - 17 - Archivio film fwrite (&filmcorrente, sizeof(film), 1, archivio); scambio = vero; while (scambio); fclose (archivio); - 18-9
Archivio film void inserisci (char nomefile[]) FILE *archivio; Film nuovofilm; /* apertura file per scrivere in append */ archivio = fopen (nomefile, "ab"); printf ("Codice film diverso da 0: "); scanf ("%u", &nuovofilm.codice); if (nuovofilm.codice!= 0) printf ("Titolo film: "); scanf ("%s", nuovofilm.titolo); - 19 - Archivio film while (nuovofilm.codice!= 0) fwrite (&nuovofilm, sizeof(nuovofilm), 1, archivio); printf ("Codice film diverso da 0: "); scanf ("%u", &nuovofilm.codice); if (nuovofilm.codice!= 0) printf ("Titolo film: "); scanf ("%s", nuovofilm.titolo); fclose (archivio); ordina (nomefile); /* riordina tutto il file */ - 20-10
Archivio film void cerca (char nomefile[]) typedef enum falso, vero Booleano; Booleano trovato = falso; FILE *archivio; Film filmcorrente; unsigned int codcercato; int inizio, fine, medio; printf ("Codice cercato: "); scanf ("%u", &codcercato); archivio = fopen (nomefile, "rb"); inizio = 0; fseek (archivio, -sizeof(film), SEEK_END); fine = ftell (archivio) / sizeof(film); - 21 - Archivio film do medio = (inizio + fine) / 2; fseek (archivio, medio * sizeof(film), SEEK_SET); fread (&filmcorrente, sizeof(filmcorrente), 1, archivio); if (codcercato < filmcorrente.codice) fine = medio - 1; else if (codcercato > filmcorrente.codice) inizio = medio + 1; - 22-11
Archivio film else trovato = vero; while (!trovato && inizio <= fine); if (trovato) printf ("Trovato in posiz: %u\n", medio); printf("codice: %u\n",filmcorrente.codice); printf("titolo: %s\n",filmcorrente.titolo); else printf ("Non trovato!\n"); fclose (archivio); - 23 - Archivio film unsigned int menu () unsigned int scelta; printf ("1. Inserisci elenco film\n"); printf ("2. Cerca film\n"); printf ("3. Esci\n"); printf ("\nscelta: "); scanf ("%u", &scelta); return scelta; - 24-12
Archivio film void main() char nomearchivio[] = "numeri.dat"; unsigned int n; do n = menu(); switch (n) case 1: inserisci (nomearchivio); case 2: while (n!= 3); break; cerca (nomearchivio); break; - 25 - Riepilogo sui file Le funzioni fscanf(), fread(), fprintf(), fwrite() leggono/scrivono a partire dalla posizione corrente della testina all interno del file Dopo l operazione, la testina si sposta in avanti di una quantità di byte pari al numero di byte letti/scritti Il tipo del dato letto dal file deve essere in accordo con quanto la funzione si aspetta: Se un file contiene una stringa e lo leggo con: fscanf (file, "%d", &varintera); la variabile varintera conterrà un valore scorretto! Idem per quanto riguarda fread(). - 26-13
Riepilogo sui file Uso di sizeof() con fread() e fwrite(): Quando leggo/scrivo variabili che non siano vettori, uso il nome della variabile: int v; fread (&v, sizeof(v), 1, ilfile); Quando leggo/scrivo variabili vettore, uso: Il nome della variabile, per leggere/scrivere tutto il vettore in un colpo solo: int vet[10]; fread (vet, sizeof(vet), 1, ilfile); Il nome del tipo, per leggere/scrivere solo una cella del vettore: int vet[10], i = 0; fread (&vet[i], sizeof(int), 1, ilfile); - 27 - Riepilogo sui file File di testo o binari? Quando è richiesto di leggere/scrivere delle variabili strutturate, si usano i file binari Quando è richiesto di spostarsi all interno del file (fseek()), si usano i file binari Quando è richiesto di leggere/scrivere stringhe di caratteri, si usano (tipicamente) file di testo Quando scrivo con fprintf(), leggo con fscanf(), quando scrivo con fwrite(), leggo con fread(). - 28-14
Puntatori char *p, s[]= xyz ; p = s; p x y z \0 s int *p2; p2 = 23; oppure int *p3; *p3 = 23; oppure int *p4, var; p4 = &var; *p4 = 23; p2 p4-29 - 23 p3 99 Es. di valore casuale 23 var Indirizzo: 23? Indirizzo: 99 23 Puntatori Dato il seguente frammento di programma C: int *p1, *p2, x, y; x = 10; y = 20; p1 = &x; p2 = p1; *p1 = 5; p2 = &y; y = 30; *p2 = *p1 + *p2; *p1 = *p1 + x; Disegnare il valore di tutte le variabili al termine dell esecuzione di ogni riga. Le variabili x e y si trovano, rispettivamente, nelle celle di memoria di indirizzo 1000 e 2000. - 30-15
Puntatori int *p1, *p2, x, y; x = 10; y = 20; p1 = &x; p2 = p1; 1000 2000 p1 x y p2????? 10??? 10 20? 1000 10 20? 1000 10 20 1000-31 - Puntatori *p1 = 5; p2 = &y; y = 30; *p2 = *p1 + *p2; *p1 = *p1 + x; 1000 2000 p1 x y p2 1000 5 20 1000 1000 5 20 2000 1000 5 30 2000 1000 5 35 2000 1000 10 35 2000-32 - 16
Le liste dinamiche - 33 - Le liste dinamiche: operazioni tipiche Inserimento di un elemento: In testa alla lista In coda alla lista In un punto generico (equivale ad inserire in testa ad una sotto-lista) Cancellazione di un elemento: Dalla testa Dalla coda Da un punto generico (equivale a cancellare la testa di una sotto-lista) Cancellazione totale della lista Ricerca Stampa della lista Ordinamento - 34-17
Le liste dinamiche: definizione #include <stdio.h> #include <stdlib.h> struct Elem int dato; struct Elem *prox; ; typedef struct Elem ElementoLista; typedef ElementoLista *Lista; - 35 - Le liste dinamiche: libreria di funzioni Lista inserisciintesta (Lista lista, int dato); Lista inserisciincoda (Lista lista, int dato); Lista cancellatesta (Lista lista); Lista cancellacoda (Lista lista); Lista cancellalista (Lista lista); Lista cercainlista (Lista lista, int dato); void scrivilista (Lista lista); In un caso reale, sostituirò int con il tipo che mi interessa Per esempio, potrei definire il tipo CartaIdentita e costruire quindi un lista di carte di identità. - 36-18
Le liste dinamiche: il main void main() unsigned int num, i; int d, cercato; Lista lamialista, elem; /* Nessuna limitazione a priori! */ printf ("Quanti dati? "); scanf ("%u", &num); for (i = 0; i < num; i++) printf ("Dato: "); scanf ("%d", &d); lamialista=inserisciincoda(lamialista,d); printf ("Dato da cercare: "); scanf ("%d", &cercato); - 37 - Le liste dinamiche: il main scrivilista(lamialista); elem = cercainlista (lamialista, cercato); if (elem!= NULL) printf ("Dato cercato: %d\n", elem->dato); else printf ("Dato non trovato\n"); lamialista = cancellatesta (lamialista); scrivilista(lamialista); lamialista = cancellacoda (lamialista); scrivilista(lamialista); lamialista = cancellalista (lamialista); scrivilista(lamialista); - 38-19
Le liste dinamiche: inserisci in testa Lista inserisciintesta (Lista lista, int dato) Lista nuovoelem; nuovoelem=(lista)malloc(sizeof(elementolista)); nuovoelem->dato = dato; nuovoelem->prox = lista; return nuovoelem; Dopo ogni inserimento, lista (il puntatore alla testa della lista) viene modificato. - 39 - Le liste dinamiche: inserisci in coda Lista inserisciincoda (Lista lista, int dato) Lista nuovoelem, cursore; nuovoelem=(lista)malloc(sizeof(elementolista)); nuovoelem->dato = dato; nuovoelem->prox = NULL; if (lista == NULL) return nuovoelem; else cursore = lista; while (cursore->prox!= NULL) cursore = cursore->prox; cursore->prox = nuovoelem; return lista; - 40-20
Le liste dinamiche: inserisci in coda Due casi: Lista vuota il nuovo elemento è il primo della lista; la funzione ne ritorna l indirizzo Lista non vuota arriva all ultimo elemento e vi appende il nuovo. Nel secondo caso, lista non viene modificato La funzione deve comunque ritornare qualcosa: ritorna lista - 41 - Le liste dinamiche: cancella la testa Lista cancellatesta (Lista lista) Lista temp; temp = lista->prox; free (lista); return temp; Dopo ogni cancellazione, lista (il puntatore alla testa della lista) viene modificato. - 42-21
Le liste dinamiche: cancella la coda Lista cancellacoda (Lista lista) Lista cursore; if (lista == NULL) return lista; else if (lista->prox == NULL) free (lista); return NULL; - 43 - Le liste dinamiche: cancella la coda else cursore = lista; while (cursore->prox->prox!= NULL) cursore = cursore->prox; free (cursore->prox); cursore->prox = NULL; return lista; - 44-22
Le liste dinamiche: cancella la coda Tre casi: Lista già vuota non fa nulla Lista composta da un solo elemento la testa punta a NULL Lista composta da più elementi il penultimo punta a NULL - 45 - Le liste dinamiche: cancellazione totale Lista cancellalista (Lista lista) Lista temp, cursore; cursore = lista; while (cursore!= NULL) temp = cursore->prox; free (cursore); cursore = temp; return cursore; Come potrei definirla usando le funzioni cancellatesta() o cancellacoda()? - 46-23
Le liste dinamiche: ricerca Lista cercainlista (Lista lista, int dato) Lista cursore; int trovato = 0; cursore = lista; while (cursore!= NULL && trovato == 0) if (cursore->dato == dato) trovato = 1; else cursore = cursore->prox; if (trovato == 1) return cursore; else return NULL; - 47 - Le liste dinamiche: ricerca Ricerca lineare: parto dal primo elemento e vado avanti Non molto efficiente (la ricerca binaria è molto più veloce) Ma, posso fare diversamente? Liste accesso sequenziale! - 48-24
Le liste dinamiche: scrivi lista void scrivilista (Lista lista) Lista cursore; printf ("Inizio lista\n"); cursore = lista; while (cursore!= NULL) printf ("%d\n", cursore->dato); cursore = cursore->prox; printf ("Fine lista\n"); - 49 - Le liste dinamiche: conclusione Allocazione dinamica il programmatore non è obbligato a porre dei limiti al numero di dati da memorizzare in RAM Prendo spazio quando serve, usando la malloc() Libero spazio quando posso, usando la free() Scomodo i vettori sono più facili da usare Non esistono pasti gratis!!! Accesso solo sequenziale Idem come sopra!!! - 50-25