esercizi - corsi.dei.polimi.itcorsi.dei.polimi.it/infoa/slide14.pdf · 1 politecnico di milano...
TRANSCRIPT
1
PolitecnicoPolitecnicodi Milanodi Milano
EserciziEsercizi
EserciziEsercizi di di riepilogoriepilogo sulsul linguaggiolinguaggio C: file, C: file, puntatoripuntatori, , listeliste
-- 22 --
Codifica file di testoCodifica 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
-- 33 --
Codifica file di testoCodifica file di testo
#include <stdio.h>#include <string.h>
const unsigned int CRIPTA = 0;const unsigned int DECRIPTA = 1;
void codificaCesare ( char *car, unsigned int k,unsigned int azione)
{int temp;
.
-- 44 --
Codifica file di testoCodifica file di testo
if (azione == CRIPTA){
*car = *car - 'a' ;temp = *car + k;if (temp < 26){
*car = temp;}else{
*car = temp - 26;}*car = *car + 'a' ;
}.
3
-- 55 --
Codifica file di testoCodifica file di testo
else /* decripta */{
*car = *car - 'a' ;temp = *car - k;if (temp >= 0){
*car = temp;}else{
*car = temp + 26;}*car = *car + 'a' ;
}}
.
-- 66 --
Codifica file di testoCodifica 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);
} .
4
-- 77 --
Codifica file di testoCodifica 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);
} .
-- 88 --
Elimina Elimina tagtag HTMLHTML
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 >
5
-- 99 --
Elimina Elimina tagtag HTMLHTML
#include <stdio.h>
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;}
-- 1010 --
Elimina Elimina tagtag HTMLHTML
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;}
}
6
-- 1111 --
Elimina Elimina tagtag HTMLHTML
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);
}
-- 1212 --
Elimina Elimina tagtag HTMLHTML
void main(){
char nomeFileHTML[ 255 ], nomeFileTesto[ 255 ];
printf ( "Nome file HTML: " );scanf ( "%s" , nomeFileHTML);printf ( "Nome file testo: " );scanf ( "%s" , nomeFileTesto);eliminaTag (nomeFileHTML, nomeFileTesto);
}
7
-- 1313 --
Archivio filmArchivio 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?
-- 1414 --
Archivio film: ricerca binariaArchivio film: ricerca binaria
0
Valore della variabile inizio
2
Valore della variabile fine
1
Valore della variabile medio
fseek (archivio, - sizeof(Film), SEEK_END);
Posizione iniziale all’apertura del file
Posizione dopo fseek()
inizio = 0;fine = ftell(archivio) / sizeof(Film);medio = (inizio + fine) / 2;
102 2030 101 204 305306
archivio = fopen ( "pippo" , "rb" );
8
-- 1515 --
Archivio filmArchivio 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;
-- 1616 --
Archivio filmArchivio film
/* "r+b" permette di leggere/scrivere sufile 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);
9
-- 1717 --
Archivio filmArchivio 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);
-- 1818 --
Archivio filmArchivio film
fwrite (&filmCorrente,sizeof(Film), 1,archivio);
scambio = vero ;}
}} while (scambio);fclose (archivio);
}
10
-- 1919 --
Archivio filmArchivio 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);
}
-- 2020 --
Archivio filmArchivio 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 */
}
11
-- 2121 --
Archivio filmArchivio 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);
-- 2222 --
Archivio filmArchivio 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;}
12
-- 2323 --
Archivio filmArchivio 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);
}
-- 2424 --
Archivio filmArchivio 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;
}
13
-- 2525 --
Archivio filmArchivio film
void main(){
char nomeArchivio[] = "numeri.dat" ;unsigned int n;do{
n = menu();switch (n){
case 1: inserisci (nomeArchivio);break;
case 2: cerca (nomeArchivio);break;
}} while (n != 3);
}
-- 2626 --
Riepilogo sui file…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().
14
-- 2727 --
Riepilogo sui file…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);
-- 2828 --
Riepilogo sui file…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() .
15
-- 2929 --
PuntatoriPuntatori
char *p, s[]= “xyz” ;
p = s;
int *p2;
p2 = 23;
oppure…
int *p3;
*p3 = 23;
oppure…
int *p4, var;
p4 = &var;
*p4 = 23;
?23p2Indirizzo: 23
23p4 var
23p3 99Indirizzo: 99
Es. di valore casuale
\0zyxp s
-- 3030 --
PuntatoriPuntatori
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.
16
-- 3131 --
PuntatoriPuntatori
int *p1, *p2, x, y;
x = 10;
y = 20;
p1 = &x;
p2 = p1;
? ? ? ?
? 10 ? ?
? 10 20 ?
1000 10 20 ?
1000 10 20 1000
p1 x y p21000 2000
-- 3232 --
PuntatoriPuntatori
*p1 = 5;
p2 = &y;
y = 30;
*p2 = *p1 + *p2;
*p1 = *p1 + x;
1000 5 20 1000
1000 5 20 2000
1000 5 30 2000
1000 5 35 2000
1000 10 35 2000
p1 x y p21000 2000
17
-- 3333 --
Le liste dinamicheLe liste dinamiche
-- 3434 --
Le liste dinamiche: operazioni tipicheLe 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
18
-- 3535 --
Le liste dinamiche: definizioneLe liste dinamiche: definizione
#include <stdio.h>#include <stdlib.h>
struct Elem{
int dato; struct Elem *prox;
};
typedef struct Elem ElementoLista;typedef ElementoLista *Lista;
-- 3636 --
Le liste dinamiche: “libreria” di funzioniLe 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 CartaIdentitae costruire quindi un lista di carte di identità.
19
-- 3737 --
Le liste dinamiche: il Le liste dinamiche: il mainmain
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);
-- 3838 --
Le liste dinamiche: il Le liste dinamiche: il mainmain
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);
}
20
-- 3939 --
Le liste dinamiche: inserisci in testaLe 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.
-- 4040 --
Le liste dinamiche: inserisci in codaLe 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;
}}
21
-- 4141 --
Le liste dinamiche: inserisci in codaLe 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
-- 4242 --
Le liste dinamiche: cancella la testaLe 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.
22
-- 4343 --
Le liste dinamiche: cancella la codaLe 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;
}
-- 4444 --
Le liste dinamiche: cancella la codaLe liste dinamiche: cancella la coda
else{
cursore = lista;while (cursore->prox->prox != NULL){
cursore = cursore->prox;}free (cursore->prox);cursore->prox = NULL;return lista;
}}
23
-- 4545 --
Le liste dinamiche: cancella la codaLe 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
-- 4646 --
Le liste dinamiche: cancellazione totaleLe 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() ?
24
-- 4747 --
Le liste dinamiche: ricercaLe 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;
elsecursore = cursore->prox;
}if (trovato == 1)
return cursore;else
return NULL;}
-- 4848 --
Le liste dinamiche: ricercaLe 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!
25
-- 4949 --
Le liste dinamiche: scrivi listaLe 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" );
}
-- 5050 --
Le liste dinamiche: conclusioneLe 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!!!