Programmazione 1 - Vincenzo Marra - Università degli Studi di Milano

Transcript

Programmazione 1 - Vincenzo Marra - Università degli Studi di Milano
I/O standard: i file
Strutture
Programmazione 1
Lezione 10
Vincenzo Marra
[email protected]
Dipartimento di Matematica Federigo Enriques
Università degli Studi di Milano
20 maggio 2015
I/O standard: i file
Strutture
Input/Output standard: i file
Il compilatore C assume l’esistenza nel sistema di tre flussi di
dati standard:
1
stdin – associato d’ufficio ai dati in ingresso provenienti
dalla tastiera.
2
stdout – associato d’ufficio ai dati in uscita visualizzati sul
monitor del calcolatore.
3
stderr – associato d’ufficio ai dati in uscita visualizzati sul
monitor del calcolatore. (Non ne parleremo in dettaglio.)
I/O standard: i file
Strutture
Input/Output standard: i file
Il compilatore C assume l’esistenza nel sistema di tre flussi di
dati standard:
1
stdin – associato d’ufficio ai dati in ingresso provenienti
dalla tastiera.
2
stdout – associato d’ufficio ai dati in uscita visualizzati sul
monitor del calcolatore.
3
stderr – associato d’ufficio ai dati in uscita visualizzati sul
monitor del calcolatore. (Non ne parleremo in dettaglio.)
Un file che risieda nella memoria di massa del calcolatore può
essere usato dai programmi in C come flusso di dati, sia in
lettura che in scrittura. Le funzioni della libreria standard
necessarie allo scopo sono definite nel file di intestazione
stdio.h.
I/O standard: i file
Strutture
Apertura dei file
Prima di poter leggere da o scrivere su un file, è necessario
aprirlo tramite la funzione:
FILE *fopen(char *nome, char *modo)
I/O standard: i file
Strutture
Apertura dei file
Prima di poter leggere da o scrivere su un file, è necessario
aprirlo tramite la funzione:
FILE *fopen(char *nome, char *modo)
1
La stringa nome è il nome del file, comprensivo del percorso (assoluto o relativo al punto del file system in cui
risiede il programma).
I/O standard: i file
Strutture
Apertura dei file
Prima di poter leggere da o scrivere su un file, è necessario
aprirlo tramite la funzione:
FILE *fopen(char *nome, char *modo)
1
2
La stringa nome è il nome del file, comprensivo del percorso (assoluto o relativo al punto del file system in cui
risiede il programma).
La stringa modo stabilisce la modalità di apertura del file
— per esempio, in lettura — e sarà discussa fra poco.
I/O standard: i file
Strutture
Apertura dei file
Prima di poter leggere da o scrivere su un file, è necessario
aprirlo tramite la funzione:
FILE *fopen(char *nome, char *modo)
1
2
3
La stringa nome è il nome del file, comprensivo del percorso (assoluto o relativo al punto del file system in cui
risiede il programma).
La stringa modo stabilisce la modalità di apertura del file
— per esempio, in lettura — e sarà discussa fra poco.
FILE è un tipo (definito da stdio.h, non primitivo come
int o char) i cui valori descrivono file del file system.
I/O standard: i file
Strutture
Apertura dei file
Prima di poter leggere da o scrivere su un file, è necessario
aprirlo tramite la funzione:
FILE *fopen(char *nome, char *modo)
1
2
3
4
La stringa nome è il nome del file, comprensivo del percorso (assoluto o relativo al punto del file system in cui
risiede il programma).
La stringa modo stabilisce la modalità di apertura del file
— per esempio, in lettura — e sarà discussa fra poco.
FILE è un tipo (definito da stdio.h, non primitivo come
int o char) i cui valori descrivono file del file system.
La funzione restituisce un puntatore a FILE. Esso è null
se, e solo se, si è riscontrato un errore.
I/O standard: i file
Strutture
Modalità di apertura dei file
Una chiamata alla funzione:
FILE *fopen(char *nome, char *modo)
stabilisce la modalità di apertura del file tramite la stringa modo.
I/O standard: i file
Strutture
Modalità di apertura dei file
Una chiamata alla funzione:
FILE *fopen(char *nome, char *modo)
stabilisce la modalità di apertura del file tramite la stringa modo.
1
Se modo è "r" (read), il file è aperto in lettura. Se esso è inesistente la funzione restituisce NULL e si ha un errore.
I/O standard: i file
Strutture
Modalità di apertura dei file
Una chiamata alla funzione:
FILE *fopen(char *nome, char *modo)
stabilisce la modalità di apertura del file tramite la stringa modo.
1
2
Se modo è "r" (read), il file è aperto in lettura. Se esso è inesistente la funzione restituisce NULL e si ha un errore.
Se modo è "w" (write), il file è aperto in scrittura. Se esso già
esiste viene interamente cancellato. Se invece è insistente, viene
creato.
I/O standard: i file
Strutture
Modalità di apertura dei file
Una chiamata alla funzione:
FILE *fopen(char *nome, char *modo)
stabilisce la modalità di apertura del file tramite la stringa modo.
1
2
3
Se modo è "r" (read), il file è aperto in lettura. Se esso è inesistente la funzione restituisce NULL e si ha un errore.
Se modo è "w" (write), il file è aperto in scrittura. Se esso già
esiste viene interamente cancellato. Se invece è insistente, viene
creato.
Se modo è "a" (append), il file è aperto in modalità di scrittura
accodamento: le operazioni di scrittura aggiungono i dati da
scrivere alla fine del file. Se esso è insistente, viene creato.
I/O standard: i file
Strutture
Modalità di apertura dei file
Una chiamata alla funzione:
FILE *fopen(char *nome, char *modo)
stabilisce la modalità di apertura del file tramite la stringa modo.
1
2
3
4
Se modo è "r" (read), il file è aperto in lettura. Se esso è inesistente la funzione restituisce NULL e si ha un errore.
Se modo è "w" (write), il file è aperto in scrittura. Se esso già
esiste viene interamente cancellato. Se invece è insistente, viene
creato.
Se modo è "a" (append), il file è aperto in modalità di scrittura
accodamento: le operazioni di scrittura aggiungono i dati da
scrivere alla fine del file. Se esso è insistente, viene creato.
Se si tenta di eseguire una di queste operazioni, ma non se ne
hanno i permessi, la funzione restituisce NULL.
I/O standard: i file
1
Strutture
Nota. Le modalità appena viste non permettono di eseguire lettura da e scrittura su il medesimo file aperto tramite un singolo
puntatore a FILE. Letture e scritture concorrenti sono possibili
in C tramite altre modalità di apertura, cui accenneremo solo
brevemente.
I/O standard: i file
1
2
3
4
Strutture
Nota. Le modalità appena viste non permettono di eseguire lettura da e scrittura su il medesimo file aperto tramite un singolo
puntatore a FILE. Letture e scritture concorrenti sono possibili
in C tramite altre modalità di apertura, cui accenneremo solo
brevemente.
Se modo è "r+" (read update), il file è aperto in lettura e scrittura.
Se modo è "w+" (write update), il file è aperto in scrittura e
lettura.
Se modo è "a+" (append update), il file è aperto in modalità di
lettura e accodamento.
I/O standard: i file
1
2
3
4
5
Strutture
Nota. Le modalità appena viste non permettono di eseguire lettura da e scrittura su il medesimo file aperto tramite un singolo
puntatore a FILE. Letture e scritture concorrenti sono possibili
in C tramite altre modalità di apertura, cui accenneremo solo
brevemente.
Se modo è "r+" (read update), il file è aperto in lettura e scrittura.
Se modo è "w+" (write update), il file è aperto in scrittura e
lettura.
Se modo è "a+" (append update), il file è aperto in modalità di
lettura e accodamento.
Per poter usare queste modalità di apertura occorre gestire la
posizione corrente all’interno del file fra le letture e le scritture,
tramite funzioni quali fseek o fflush.
I/O standard: i file
1
2
3
4
Strutture
Nota. Le modalità appena viste non permettono di eseguire lettura da e scrittura su il medesimo file aperto tramite un singolo
puntatore a FILE. Letture e scritture concorrenti sono possibili
in C tramite altre modalità di apertura, cui accenneremo solo
brevemente.
Se modo è "r+" (read update), il file è aperto in lettura e scrittura.
Se modo è "w+" (write update), il file è aperto in scrittura e
lettura.
Se modo è "a+" (append update), il file è aperto in modalità di
lettura e accodamento.
5
Per poter usare queste modalità di apertura occorre gestire la
posizione corrente all’interno del file fra le letture e le scritture,
tramite funzioni quali fseek o fflush.
6
I dettagli sono in K&R, Cap. 7 e §1 dell’Appendice B.
I/O standard: i file
Strutture
Chiusura dei file
Quando un file aperto non è più usato dal programma, lo si può
chiudere tramite la funzione:
int *fclose(FILE *pf)
I/O standard: i file
Strutture
Chiusura dei file
Quando un file aperto non è più usato dal programma, lo si può
chiudere tramite la funzione:
int *fclose(FILE *pf)
1
Il parametro pf è il puntatore al file da chiudere.
I/O standard: i file
Strutture
Chiusura dei file
Quando un file aperto non è più usato dal programma, lo si può
chiudere tramite la funzione:
int *fclose(FILE *pf)
1
2
Il parametro pf è il puntatore al file da chiudere.
La funzione restituisce 0 se l’operazione di chiusura è stata
eseguita con successo, e EOF altrimenti.
I/O standard: i file
Strutture
Chiusura dei file
Quando un file aperto non è più usato dal programma, lo si può
chiudere tramite la funzione:
int *fclose(FILE *pf)
1
Il parametro pf è il puntatore al file da chiudere.
2
La funzione restituisce 0 se l’operazione di chiusura è stata
eseguita con successo, e EOF altrimenti.
3
Un errore durante la chiusura si può riscontrare, per esempio,
perché pf è NULL o perché esso non è correttamente associato a
un file aperto.
I/O standard: i file
Strutture
Chiusura dei file
Quando un file aperto non è più usato dal programma, lo si può
chiudere tramite la funzione:
int *fclose(FILE *pf)
1
Il parametro pf è il puntatore al file da chiudere.
2
La funzione restituisce 0 se l’operazione di chiusura è stata
eseguita con successo, e EOF altrimenti.
3
Un errore durante la chiusura si può riscontrare, per esempio,
perché pf è NULL o perché esso non è correttamente associato a
un file aperto.
4
I file che risultino ancora aperti al momento della terminazione
(non anomala) del programma sono automaticamente chiusi.
I/O standard: i file
Strutture
Chiusura dei file
Quando un file aperto non è più usato dal programma, lo si può
chiudere tramite la funzione:
int *fclose(FILE *pf)
1
È però sempre una buona idea chiudere esplicitamente i file che
non servono più, perché le risorse del sistema operativo sono
limitate ed occorre usarle efficientemente.
I/O standard: i file
Strutture
Chiusura dei file
Quando un file aperto non è più usato dal programma, lo si può
chiudere tramite la funzione:
int *fclose(FILE *pf)
1
È però sempre una buona idea chiudere esplicitamente i file che
non servono più, perché le risorse del sistema operativo sono
limitate ed occorre usarle efficientemente.
2
Oltre a chiudere il file, la chiamata alla funzione forza la scrittura fisica sul file dei dati in uscita che ancora risiedano nella
memoria tampone (buffer) in attesa di essere trasferiti. Tutti i
sistemi operativi moderni usano tecniche più o meno sofisticate
di bufferizzazione dell’I/O, che noi però non potremo spiegare
in dettaglio. Si tratta di argomenti che si studiano nei corsi di
Sistemi Operativi.
I/O standard: i file
Strutture
Lettura e scrittura di caratteri singoli
int getc(FILE *pf)
Restituisce il successivo carattere del file pf, che deve essere
aperto in lettura, come intero (ossia il suo codice ASCII convertito da char a int), oppure EOF se incontra la fine del file o
riscontra un errore.
Nota. A differenza della lettura da stdin, la lettura da file non
è mai bloccante. Ciò vale anche per tutte le altre funzioni di
lettura da file.
I/O standard: i file
Strutture
Lettura e scrittura di caratteri singoli
int getc(FILE *pf)
Restituisce il successivo carattere del file pf, che deve essere
aperto in lettura, come intero (ossia il suo codice ASCII convertito da char a int), oppure EOF se incontra la fine del file o
riscontra un errore.
Nota. A differenza della lettura da stdin, la lettura da file non
è mai bloccante. Ciò vale anche per tutte le altre funzioni di
lettura da file.
int putc(int c, FILE *pf)
Scrive il carattere c, convertito in int, sul file pf, che deve essere aperto in scrittura. Restituisce il carattere scritto oppure EOF
se incorre in un errore.
I/O standard: i file
Strutture
Esercizio: Eco da file
Si scriva un programma che accetti da riga di comando il nome
di un file, e lo visualizzi sul terminale carattere per carattere.
Se il nome del file non è specificato o è inesistente o non può
essere aperto, il programma termina con un messaggio d’errore
appropriato
I/O standard: i file
Strutture
feco.c
1
#include <stdio.h>
2
3
4
5
6
7
8
9
int main(int argc, char *argv[]) //ah, e’ lui
{
if (argc < 2)
{
printf("Errore nel numero degli argomenti.\n");
return -1;
}
10
FILE *pf;
if ( (pf=fopen(argv[1], "r")) == NULL )
{
printf("Errore nell’apertura del file: \"%s\".\n", argv[1]);
return -1;
}
11
12
13
14
15
16
17
/* Esegue l’eco a video, carattere per carattere */
char c;
while ( (c=getc(pf)) != EOF )
putchar(c);
18
19
20
21
22
return 0;
23
24
}
I/O standard: i file
Strutture
Lettura e scrittura di dati formattati
int fscanf (FILE *pf, const char *formato, ...)
int fprintf (FILE *pf, const char *formato, ...)
Queste due funzioni sono identiche alle loro controparti scanf
e printf, eccetto che il primo argomento indica il file dal o sul
quale leggere o scrivere, rispettivamente.
In altre parole,
int fscanf (stdin, const char *formato, ...)
int fprintf (stdout, const char *formato, ...)
sono identiche a scanf e printf, che già conosciamo.
I/O standard: i file
Strutture
Lettura e scrittura di stringhe
char *fgets (char *s, int max, FILE *pf)
L’abbiamo già citata. Legge la prossima riga da pf, fino al più a
max-1 caratteri, pone quanto letto in s, aggiungendo in coda il
terminatore '\0'.
Nota. Include anche l’eventuale '\n' fra i caratteri letti.
Restituisce il puntatore s, oppure NULL se incontra la fine del file
o se riscontra un errore.
I/O standard: i file
Strutture
Lettura e scrittura di stringhe
char *fgets (char *s, int max, FILE *pf)
L’abbiamo già citata. Legge la prossima riga da pf, fino al più a
max-1 caratteri, pone quanto letto in s, aggiungendo in coda il
terminatore '\0'.
Nota. Include anche l’eventuale '\n' fra i caratteri letti.
Restituisce il puntatore s, oppure NULL se incontra la fine del file
o se riscontra un errore.
int fputs (char *s, FILE *pf)
Scrive la stringa s sul file pf.
Restituisce un valore non negativo se la chiamata va a buon fine,
e EOF se riscontra un errore.
I/O standard: i file
Strutture
scrivileggi.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<stdio.h>
int main(void)
{
FILE *pf; //puntatore a file
char letta[BUFSIZ]; //buffer di lettura
char s[]="Ego te absolvo..."; //una stringa
if ((pf=fopen("test", "a")) == NULL) //pf e’ associato al file "test"
{
printf("Errore I/O.\n");
return 0;
}
fprintf(pf, "Ecco un intero: %d\n", 45);
fprintf(pf, "Ecco un double: %lf\n", 3.1415);
fprintf(pf, "Ecco una stringa: %s\n", s);
fclose(pf);
if ((pf=fopen("test", "r")) == NULL) //pf e’ associato al file "test"
{
printf("Errore I/O.\n");
return 0;
}
while ( fgets(letta, BUFSIZ, pf)!= NULL ) //stampa su stdout una riga alla volta.
printf("%s",letta);
fclose(pf);
return 0;
}
I/O standard: i file
Strutture
Lettura di stringhe: funzioni deprecate e sicurezza
Abbiamo già visto la funzione
char ∗ gets(char ∗ s)
Essa è “deprecata” dagli standard C recenti, e non va mai usata in
programmi reali. (Si usa fgets al suo posto, anche per leggere da
stdin.) A fini didattici, per l’esame, è permesso usarla: sarebbe però
preferibile abituarsi fin da subito all’uso di fgets.
I/O standard: i file
Strutture
Lettura di stringhe: funzioni deprecate e sicurezza
Abbiamo già visto la funzione
char ∗ gets(char ∗ s)
Essa è “deprecata” dagli standard C recenti, e non va mai usata in
programmi reali. (Si usa fgets al suo posto, anche per leggere da
stdin.) A fini didattici, per l’esame, è permesso usarla: sarebbe però
preferibile abituarsi fin da subito all’uso di fgets.
Il motivo per cui l’uso di gets è deprecato è che i programmi che la
usano possono andare in buffer overflow: per cenni, ciò accade perché
gets può leggere più caratteri dello spazio di memoria (buffer) che il
programmatore ha allocato per memorizzarli, il che può permette a
un programma malevolo (malware) di attaccare il programma in
questione e accedere al sistema su cui esso gira. Sono argomenti
trattati nei corsi di Sicurezza Informatica.
I/O standard: i file
Strutture
Le strutture
Le strutture permettono di accorpare in una singola unità sintattica
tipi di dati compositi. Per esempio, possiamo denotare un punto del
piano reale con una coppia di double, le sue coordinate. Per
accorpare le due coordinate in una singola unità, dichiariamo:
1
2
3
4
5
struct punto //Etichetta (opzionale) della struttura
{
double x; //Primo membro
double y; //Secondo membro
};
I/O standard: i file
Strutture
Le strutture
Le strutture permettono di accorpare in una singola unità sintattica
tipi di dati compositi. Per esempio, possiamo denotare un punto del
piano reale con una coppia di double, le sue coordinate. Per
accorpare le due coordinate in una singola unità, dichiariamo:
1
2
3
4
5
struct punto //Etichetta (opzionale) della struttura
{
double x; //Primo membro
double y; //Secondo membro
};
Fatto centrale. Queste righe d codice definiscono un nuovo tipo
(senza allocare memoria).
I/O standard: i file
Strutture
Le strutture
Le strutture permettono di accorpare in una singola unità sintattica
tipi di dati compositi. Per esempio, possiamo denotare un punto del
piano reale con una coppia di double, le sue coordinate. Per
accorpare le due coordinate in una singola unità, dichiariamo:
1
2
3
4
5
struct punto //Etichetta (opzionale) della struttura
{
double x; //Primo membro
double y; //Secondo membro
};
Fatto centrale. Queste righe d codice definiscono un nuovo tipo
(senza allocare memoria). Esso è il tipo struct punto.
I/O standard: i file
Strutture
Le strutture
Le strutture permettono di accorpare in una singola unità sintattica
tipi di dati compositi. Per esempio, possiamo denotare un punto del
piano reale con una coppia di double, le sue coordinate. Per
accorpare le due coordinate in una singola unità, dichiariamo:
1
2
3
4
5
struct punto //Etichetta (opzionale) della struttura
{
double x; //Primo membro
double y; //Secondo membro
};
Fatto centrale. Queste righe d codice definiscono un nuovo tipo
(senza allocare memoria). Esso è il tipo struct punto. Se l’etichetta
punto — che è un’abbreviazione di ciò che la segue, fino alla graffa di
chiusura — è assente, il nome del nuovo tipo va da struct (incluso)
alla graffa di chiusura.
I/O standard: i file
Strutture
Dichiarazioni di variabili
Segue che è legittimo e sensato dichiarare:
struct punto p; //Un punto (non inizializzato)
I/O standard: i file
Strutture
Dichiarazioni di variabili
Segue che è legittimo e sensato dichiarare:
struct punto p; //Un punto (non inizializzato)
Fatto centrale. Questa dichiarazione alloca memoria sufficiente a
memorizzare tutti i membri della struttura (memoria per due
double).
I/O standard: i file
Strutture
Dichiarazioni di variabili
Segue che è legittimo e sensato dichiarare:
struct punto p; //Un punto (non inizializzato)
Fatto centrale. Questa dichiarazione alloca memoria sufficiente a
memorizzare tutti i membri della struttura (memoria per due
double).
Nota che è anche legittimo e sensato il brano seguente, che codifica
dichiarazione e definizione assieme, senza etichetta:
1
2
3
4
5
struct
{
double x; //Primo membro
double y; //Secondo membro
} p,q; //Due punti (non inizializzati)
I/O standard: i file
Strutture
Inizializzazione, assegnazioni, parametri
Le variabili di tipo struct ... si possono inizializzare, al momento
della dichiarazione, con liste di valori costanti, in modo simile a
quanto abbiamo visto per gli array. Per esempio:
struct punto q = {-0.1, 2}; //Inizializzazione con lista
I/O standard: i file
Strutture
Inizializzazione, assegnazioni, parametri
Le variabili di tipo struct ... si possono inizializzare, al momento
della dichiarazione, con liste di valori costanti, in modo simile a
quanto abbiamo visto per gli array. Per esempio:
struct punto q = {-0.1, 2}; //Inizializzazione con lista
Tali variabili possono anche essere assegnate. Così, è legittimo:
1
2
3
4
5
6
7
8
struct punto //Etichetta (opzionale) della struttura
{
double x; //Primo membro
double y; //Secondo membro
};
struct punto p; //Un punto (non inizializzato)
struct punto q = {-0.1, 2}; //Inizializzazione con lista
p=q; //Assegna q a p
I/O standard: i file
Strutture
Inizializzazione, assegnazioni, parametri
Si possono poi passare le variabili automatiche di tipo struct {...}
come parametri alle funzioni. E le funzioni possono restituire valori di
un tale tipo strutturato.
Per esempio:
1
2
3
4
5
6
funzstrutt.c
/* Definizione globale */
struct punto //Etichetta (opzionale) della struttura
{
double x; //Primo membro
double y; //Secondo membro
};
7
8
9
10
11
12
/* Nel main */
struct punto O = {0.0, 0.0}; //Un punto
struct punto p = {1.0, 1.0}; //Un altro punto
struct punto m;//Un terzo punto (non inizializzato)
m=medio(O,p); //restitusice il punto medio degli args
I/O standard: i file
Strutture
Inizializzazione, assegnazioni, parametri
Si possono poi passare le variabili automatiche di tipo struct {...}
come parametri alle funzioni. E le funzioni possono restituire valori di
un tale tipo strutturato.
Il prototipo della funzione medio deve allora essere:
struct punto medio(struct punto, struct punto);
Nota. Anche qui, come sempre in C, il passaggio dei parametri
avviene per copia. Naturalmente è possibile dichiarare e passare come
argomenti puntatori a strutture. Per esempio, la dichiarazione
struct punto *pnt;
dichiara (ma non inizializza) un puntatore a struct punto.
I/O standard: i file
Strutture
Accesso ai campi
Per accedere a un membro di una struttura si usa la sintassi
nome-strutt.membro-strutt
Così:
I/O standard: i file
Strutture
Accesso ai campi
Per accedere a un membro di una struttura si usa la sintassi
nome-strutt.membro-strutt
Così:
1
2
3
4
5
struct
{
double x; //Primo membro
double y; //Secondo membro
} p; //Un punto (non inizializzato)
6
7
8
p.x=0.0; //Assegna ascissa
p.y=1.1; //Assegna ordinata
I/O standard: i file
Strutture
Campo di visibilità dei membri e shadowing
Il nome completo del membro ascissa è dunque p.x, e non solo x. La
coppia di dichiarazioni:
I/O standard: i file
Strutture
Campo di visibilità dei membri e shadowing
Il nome completo del membro ascissa è dunque p.x, e non solo x. La
coppia di dichiarazioni:
10
11
struct punto p;
int x;
non dà quindi luogo ad alcun effetto di shadowing: non vi sono
ambiguità possibili fra
p.x
che qui è la variabile di tipo double, e
x
che qui invece è la variabile di tipo int.
I/O standard: i file
Strutture
Strutture innestate
Un membro di una struttura può essere esso stesso una struttura.
Supponiamo di codificare un triangolo nel piano tramite i suoi tre
vertici. Così:
I/O standard: i file
Strutture
Strutture innestate
Un membro di una struttura può essere esso stesso una struttura.
Supponiamo di codificare un triangolo nel piano tramite i suoi tre
vertici. Così:
1
2
3
4
5
6
struct tri
{
struct punto a; //Primo membro
struct punto b; //Secondo membro
struct punto c; //Terzo membro
} t; //Un triangolo (non inizializzato)
I/O standard: i file
Strutture
Strutture innestate
Un membro di una struttura può essere esso stesso una struttura.
Supponiamo di codificare un triangolo nel piano tramite i suoi tre
vertici. Così:
1
2
3
4
5
6
struct tri
{
struct punto a; //Primo membro
struct punto b; //Secondo membro
struct punto c; //Terzo membro
} t; //Un triangolo (non inizializzato)
L’accesso ai singoli vertici si codifica così:
8
t.a={0.0,1.0}; //Inizializzazione del vert a di t
I/O standard: i file
Strutture
Strutture innestate
Un membro di una struttura può essere esso stesso una struttura.
Supponiamo di codificare un triangolo nel piano tramite i suoi tre
vertici. Così:
1
2
3
4
5
6
struct tri
{
struct punto a; //Primo membro
struct punto b; //Secondo membro
struct punto c; //Terzo membro
} t; //Un triangolo (non inizializzato)
L’accesso alle coordinate dei vertici si codifica così:
9
t.b.x=-1.0; //Inizializzazione dell’ascissa del vert b di t
I/O standard: i file
Strutture
Puntatori alle strutture e operatore ->
I puntatori alle strutture sono del tutto analoghi ai puntatori alle
variabili ordinarie. Così:
1
2
3
4
5
6
struct tri
{
struct punto a;
struct punto b;
struct punto c;
};
7
8
9
10
struct tri s, t = {{0,0}, {0,1}, {1,0}}; //Due triangoli
struct tri *pt; //Puntatore a struct tri, non inizializzato
pt=&t; //pt punta a t
I/O standard: i file
Strutture
Puntatori alle strutture e operatore ->
I puntatori alle strutture sono del tutto analoghi ai puntatori alle
variabili ordinarie. Così:
1
2
3
4
5
6
struct tri
{
struct punto a;
struct punto b;
struct punto c;
};
7
8
9
10
struct tri s, t = {{0,0}, {0,1}, {1,0}}; //Due triangoli
struct tri *pt; //Puntatore a struct tri, non inizializzato
pt=&t; //pt punta a t
Accesso al vertice a di t:
11
s.a=(*pt).a; //accede al vert a di t. Parentesi necessarie.
I/O standard: i file
Strutture
Puntatori alle strutture e operatore ->
I puntatori alle strutture sono del tutto analoghi ai puntatori alle
variabili ordinarie. Così:
1
2
3
4
5
6
struct tri
{
struct punto a;
struct punto b;
struct punto c;
};
7
8
9
10
struct tri s, t = {{0,0}, {0,1}, {1,0}}; //Due triangoli
struct tri *pt; //Puntatore a struct tri, non inizializzato
pt=&t; //pt punta a t
Accesso alla coordinata x del vertice b di t:
12
s.b.x=(*pt).b.x; //accede all’ascissa del vert b di t.
I/O standard: i file
Strutture
Puntatori alle strutture e operatore ->
I puntatori alle strutture sono del tutto analoghi ai puntatori alle
variabili ordinarie. Così:
1
2
3
4
5
6
struct tri
{
struct punto a;
struct punto b;
struct punto c;
};
7
8
9
10
struct tri s, t = {{0,0}, {0,1}, {1,0}}; //Due triangoli
struct tri *pt; //Puntatore a struct tri, non inizializzato
pt=&t; //pt punta a t
Abbreviazione ->. Accesso al vertice c di t:
13
s.c=pt->c; //accede al vert c di t.
I/O standard: i file
Strutture
Puntatori alle strutture e operatore ->
I puntatori alle strutture sono del tutto analoghi ai puntatori alle
variabili ordinarie. Così:
1
2
3
4
5
6
struct tri
{
struct punto a;
struct punto b;
struct punto c;
};
7
8
9
10
struct tri s, t = {{0,0}, {0,1}, {1,0}}; //Due triangoli
struct tri *pt; //Puntatore a struct tri, non inizializzato
pt=&t; //pt punta a t
Abbreviazione ->. Accesso alla coordinata y del vertice c di t:
14
pt->c.y=2.5; //accede all’ordinata del vert c di t.
I/O standard: i file
Strutture
Esercizi
1 Si scriva una funzione che accetti in ingresso due puntatori
a strutture che rappresentano punti nel piano, e restituisca
un puntatore al punto di norma euclidea minima.
2
Si definisca una struttura atta a rappresentare libri, nella
forma Cognome Autore, Titolo, Data Pubblicazione. Si
scriva poi una funzione che accetti in ingresso un (puntatore a un) array di tali strutture, e restituisca l’indice del
libro di pubblicazione più recente.
Segue una soluzione del primo esercizio. Il secondo sarà svolto
in classe tempo permettendo, oppure potrete risolverlo in
laboratorio.
I/O standard: i file
Strutture
norm.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include <math.h>
struct punto
{
double x;
double y;
};
double norma(struct punto *);
struct punto *minnorm(struct punto *, struct punto *);
int main(void)
{
struct punto p = {2.5,1}, q = {1,1};
printf("Dei due punti (%g,%g) e (%g,%g),", p.x,p.y,q.x,q.y);
struct punto *pt = minnorm(&p,&q);
printf("il punto di norma minima e’ (%g,%g).\n", pt->x,pt->y);
return 0;
}
double norma(struct punto *a)
{
return sqrt( (a->x)*(a->x)+(a->y)*(a->y) );
}
struct punto *minnorm(struct punto *a, struct punto *b)
{
if (norma(a) < norma (b))
return a;
return b;
}