12 struct

30
INFORMATICA Il costrutto struct

Upload: guest60e9511

Post on 19-Jun-2015

2.374 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: 12   Struct

INFORMATICA

Il costrutto struct

Page 2: 12   Struct

2 © Piero Demichelis

Il costrutto struct

• Supponiamo di dover realizzare una base dati contenente i nomi e l’anno di corso di una popolazione studentesca. Non si può ricorrere a una matrice bidimensionale con una dimensione per le variabili di tipo carattere (per i nomi) e l'altra per la variabile intera (anno di corso): le matrici possono essere di dimensioni qualsiasi ma il tipo-base deve essere unico!

• Occorrerebbe definire una matrice (vettore di vettori) di caratteri per i nomi e un vettore di interi per l'anno di corso: due strutture dati separate tra loro. Pertanto l'allineamento dei dati inerenti la stessa persona dovrà essere garantito dal programmatore mediante una efficiente politica di gestione di indici.

Page 3: 12   Struct

3 © Piero Demichelis

Il costrutto struct

• La difficoltà è superata da un altro tipo di dato strutturato, molto più flessibile: il tipo struct.

• Si tratta di una collezione di dati, anche di caratteristiche molto diverse tra loro (tipo diverso!), che però sono identificati dallo stesso nome.

 • Una struttura è formata da membri o campi. Ogni

campo rappresenta un dato (col suo tipo) della collezione.

• In questo modo dati di natura diversa (ovvero rappresentati in memoria da codici binari diversi) ma riferentesi alla stessa cosa, possono condividere lo stesso nome

Page 4: 12   Struct

4 © Piero Demichelis

Il costrutto struct

• Sono numerose le informazioni che intrinsecamente possono accordarsi con questo tipo di dato, ad esempio:

una data è composta da giorno (int), mese (char) e anno (int) e quindi si può definire una struttura composta da questi tre campi;

una persona è identificata da nome, cognome, data di nascita, codice fiscale, stato civile, indirizzo, ecc., quindi si può definire una struttura composta da tutti questi campi;

la classifica di una manifestazione sportiva è composta da nome e cognome degli atleti a cui è associata la prestazione (tempo impiegato, punti, ecc.).

Page 5: 12   Struct

5 © Piero Demichelis

Il costrutto struct

• Poiché in italiano il termine “struttura ” è usato con un'accezione più generica, viene di solito utilizzata la dizione di record, mutuata da altri linguaggi, e per i membri della struttura quella di campi.

• I campi di un record possono essere di tipo diverso, scalari, vettori o, a loro volta, altre struct.

 • Differentemente dai vettori, i cui elementi sono

identificati dal nome e dalla posizione occupata, nelle struct i singoli elementi sono identificati dal nome della struttura e dal nome del campo. 

Page 6: 12   Struct

6 © Piero Demichelis

Il costrutto struct

• Una struct viene definita elencando i nomi che si intendono attribuire ai singoli campi (identificatori di campo). Per ogni identificatore di campo poi, occorre specificare il tipo.

struct [nome_struct ] { tipo_1 variabile_1; /* campo 1 */ tipo_2 variabile_2; /* campo 2 */ .......... tipo_n variabile_n; /* campo n */ } [variabile] [,variabile]....;

dove le parti opzionali sono tra parentesi quadra.

• nome_struct costituisce il tag, cioè il nome che identifica quel particolare tipo di struttura in successive dichiarazioni di variabili.

Page 7: 12   Struct

7 © Piero Demichelis

Il costrutto struct: esempi

• definizione di una variabile di tipo record una_persona:

struct { char nome[20]; char cognome[20]; int giorno_nascita; int mese_nascita; int anno_nascita; float peso; int altezza; } una_persona;

Page 8: 12   Struct

8 © Piero Demichelis

Il costrutto struct : esempi

• definizione di un record denominato data e di una variabile day di quel tipo:

struct data { int giorno; enum {gennaio, febbraio, marzo, aprile, maggio,

giugno, luglio, agosto, settembre, ottobre, novembre, dicembre} mese; int anno; };

struct data day;

Page 9: 12   Struct

9 © Piero Demichelis

Il costrutto struct: esempi

• definizione di numero complesso dato come x + iy, dove x e y sono numeri reali e : vengono definiti la struct denominata complesso e la variabile val_complex di quel tipo record.

struct complesso { double reale; double immaginario; } val_complex;

1i

Page 10: 12   Struct

10 © Piero Demichelis

Il costrutto struct

• Le variabili possono essere dichiarate nell’ambito della stessa struttura, come succede per la variabile val_complex, oppure esternamente come nel caso di day: ad esempio, dopo le dichiarazioni precedenti, sarebbero lecite le seguenti:

struct complesso num_complesso; struct data giorno;

• I campi di una struct sono racchiusi in un blocco e quindi il loro campo di esistenza è limitato: è per questo che è lecita la definizione della variabile giorno nell’esempio precedente, pur esistendo un campo con lo stesso nome.

• Anche una funzione può essere definita di tipo struct e pertanto può restituire un valore di questo tipo.

Page 11: 12   Struct

11 © Piero Demichelis

• La dichiarazione di una struct corrisponde alla creazione di un nuovo tipo. Pertanto (come per enum) si può rinominare questo tipo mediante il typedef per ottenere una struttura del programma più comprensibile e più leggibile.

• Esempio:#include <stdio.h>……………………typedef struct { double reale; double immaginario; } complesso;

main(){complesso val_complex; /* dichiarazione della variabile

val_complex */………………………………..

Il costrutto struct

creazione del nuovo tipo

struct e ridefinizione del

nome: il nuovo tipo si

chiamerà complesso.

Page 12: 12   Struct

12 © Piero Demichelis

Il costrutto struct

• Un campo di una struct può essere un vettore, una matrice o un’altra struct. Inoltre le struct possono costituire il tipo base per la definizione di vettori.

 • Nel corso del programma si può far riferimento ad uno

specifico campo di una struct indicando l'identificatore della variabile seguito da un punto e dal nome del campo.

 • Il campo di una struct deve essere trattato come una

qualsiasi altra variabile.

• Sul tipo struct nel suo complesso non agisce alcun operatore, ma è lecita l'assegnazione di un’intera struct a un’altra struct dello stesso tipo.

• I campi delle struct mantengono invece le proprietà, e quindi gli operatori, del tipo a cui appartengono.

Page 13: 12   Struct

13 © Piero Demichelis

Il costrutto struct

• Esempio:

/* uso della struttura complesso */struct complesso { double reale; double immaginario; };

struct complesso x; ..............x.reale = 12.5;x.immaginario = 0.7;

Page 14: 12   Struct

14 © Piero Demichelis

struct: esempio

• Esempio: programma che riceve in input da tastiera delle sequenze di caratteri (parole) e calcola il numero di volte che è presente ciascun carattere (frequenza statistica). La fine dell'introduzione delle parole sia segnalata da EOF (<CTRL>+Z). Il programma dovrà visualizzare tutti i caratteri diversi introdotti e la loro frequenza statistica.

 • La base dati può essere costituita da un vettore di struct

avente due campi: un campo carattere, di tipo char, e un campo presenze, di tipo int.

 • Per ogni carattere letto da tastiera, si controlla se è già

presente: se presente, si incrementa il campo presenze di quel carattere, altrimenti lo si memorizza nel campo carattere e si pone il valore 1 nel campo presenze.

Page 15: 12   Struct

15 © Piero Demichelis

struct: esempio

#include <stdio.h>#define NUM_MAX_CAR 100

typedef enum {FALSO, VERO} boolean;

typedef struct { char carattere; int presenze; } memoria;

main(){int indice, num_car_pres;memoria vett_car[NUM_MAX_CAR]; /* vettore di strutture

*/int carat;boolean trovato;

Page 16: 12   Struct

16 © Piero Demichelis

struct: esempio

num_car_pres = 0;printf (“\nIntroduci le sequenze di caratteri.\n ");printf (" Usa <CR> per andare a capo e <EOF> per finire:\n");while ((( carat = getchar()) != EOF) && (num_car_pres <

NUM_MAX_CAR))/* finché non si arriva a EOF */ { if (carat != '\n') { /* carat è diverso da new-

line *//* cerca nella struct memoria se il carattere è già presente

*/ trovato = FALSO; indice = 0;

Page 17: 12   Struct

17 © Piero Demichelis

struct: esempio

while ((!trovato) && (indice < num_car_pres)) if (vett_car[indice].carattere == carat) { /* il carattere introdotto esiste già */

trovato = VERO; vett_car[indice].presenze++; /* incr. campo presenze */ } else indice++; /* increm. indice per scansione */

if (!trovato) { /* il carattere non c’è ancora nel vettore di struct: lo inserisce */ vett_car[num_car_pres].carattere = carat; vett_car[num_car_pres].presenze = 1; num_car_pres++; /* incr. numero di caratteri inseriti nella struct*/ } /* if not trovato */ } /* if not eoln */} /* while not eof... */

Page 18: 12   Struct

18 © Piero Demichelis

struct: esempio

/* stampa i risultati

*/ printf (“\nCarattere Presenze\n");for (indice = 0; indice < num_car_pres; indice++) { printf (" %c ", vett_car[indice].carattere); printf ("%6d\n", vett_car[indice].presenze); }}

Page 19: 12   Struct

19 © Piero Demichelis

struct come parametro di funzioni

• Le struct si comportano a tutti gli effetti come variabili di tipo semplice, con la particolarità che possono essere viste sia come un insieme aggregato, ad esempio nell'assegnazione di un record ad un altro, sia come singoli elementi (campi).

 • In quest'ultimo caso, l'identificatore dell'elemento è

costituito dal nome dell'intera struttura seguito dal punto e dal nome del campo stesso.

 • Anche una funzione può essere definita di tipo

struct e pertanto può restituire un valore di questo tipo.

Page 20: 12   Struct

20 © Piero Demichelis

struct come parametro di funzioni

Esempio: somma di due numeri complessi.

#include <stdio.h>#include <math.h> typedef struct { double reale; double immagin; } complesso;

/* prototipo della funzione per la somma dei due numeri complessi */

complesso somma_cmplx (complesso dato1, complesso dato2);  

Page 21: 12   Struct

21 © Piero Demichelis

struct come parametro di funzioni

main(){complesso x, y, total;

printf (“\nParte reale di x = "); scanf ("%lf", &x.reale);printf (“\nparte immaginaria di x = "); scanf ("%lf", &x.immagin);printf (“\nParte reale di y = "); scanf ("%lf", &y.reale);printf (“\nparte immaginaria di y = "); scanf ("%lf", &y.immagin);

total = somma_cmplx (x, y);printf (“\nLa somma vale: %f", total.reale); /* stampa della parte intera

*/if (total.immagin < 0.0) printf(" - i"); /* stampa l’operatore i */else printf(" + i");printf ("%f", fabs(total.immagin)); /* stampa parte immaginaria */}

Page 22: 12   Struct

22 © Piero Demichelis

struct come parametro di funzioni

complesso somma_cmplx (complesso dato1, complesso dato2) {complesso somma;

somma.reale = dato1.reale + dato2.reale;somma.immagin = dato1.immagin + dato2.immagin;return (somma);}

Page 23: 12   Struct

23 © Piero Demichelis

struct come parametro di funzioni

• Osservazioni: 

nel programma principale, i dati di tipo struct vengono usati come parametri di scanf e printf con le stesse modalità delle variabili di tipo semplice;

nella chiamata della funzione di tipo complesso somma_cmplx, i dati di tipo struct vengono passati by value : pertanto quando il controllo dell'esecuzione è passato alla funzione, verrà effettuata una copia delle variabili esterne nelle variabili locali della funzione dato1 e dato2;

la funzione è definita di tipo struct e restituisce un valore di tipo struct, il quale viene assegnato alla variabile total;

mediante typedef si è ridefinito il nome della struct, semplificando l'intestazione della funzione.

Page 24: 12   Struct

24 © Piero Demichelis

Esempio: punti nel piano

• In un file, il cui nome va richiesto da tastiera, ci sono le coordinate X e Y di una serie di punti appartenenti a un piano cartesiano.

Non si conosce a priori il numero di punti: si supponga siano meno di 100.

 Leggere il file, calcolare la distanza dall'origine di ogni singolo punto, quindi riordinare i punti rispetto alla distanza dall'origine (dal più vicino al più lontano).

Infine visualizzarli su monitor e salvarli (un punto per riga) in un file il cui nome va anch’esso richiesto da tastiera.

Page 25: 12   Struct

25 © Piero Demichelis

Esempio: punti nel piano

• Ad esempio se il file dei punti si chiama PUNTI.DAT e contiene:

2 2

1 4

3 3

0 1

• sul monitor dovrà apparire:

Punto 1: 0.0000, 1.0000 -> 1.0000

Punto 2: 2.0000, 2.0000 -> 2.8284

Punto 3: 1.0000, 4.0000 -> 4.1231

Punto 4: 3.0000, 3.0000 -> 4.2426

Page 26: 12   Struct

26 © Piero Demichelis

Esempio: punti nel piano

#include <stdio.h>#include <math.h>

#define NMAX 100

typedef enum {FALSO, VERO} boolean; /* “tipo” boolean */

 typedef struct /* “tipo” modello */ { double x; double y; double dist; } modello;

/* prototipo della funzione di riordinamento */void bubble (modello punti[ ], int n)

Page 27: 12   Struct

27 © Piero Demichelis

Esempio: punti nel piano

main(){ FILE *input, *output; int i, j, stato, np; char buffer[80], nomefile[20]; modello punti[NMAX]; /* vettore di strutture

*/ /* Legge il nome del file */ printf (“\nNome del file che contiene i punti: "); scanf ("%s", nomefile);/* Apre il file in lettura */ if ((input = fopen (nomefile,"r")) == NULL) { printf ("\nErrore apertura file %s", nomefile); exit (0); }

Page 28: 12   Struct

28 © Piero Demichelis

Esempio: punti nel piano

np = 0; while (fscanf (input, "%lf%lf", &punti[np].x, &punti[np].y) !=

EOF) { punti[np].dist = sqrt (punti[np].x * punti[np].x + punti[np].y * punti[np].y); np++; }

fclose (input);

bubble (punti, np);

Page 29: 12   Struct

29 © Piero Demichelis

Esempio: punti nel piano

/* Operazioni finali: chiede il nome del file di output e lo crea */ printf (“\nNome del file di output: "); scanf ("%s", nomefile); if ((output = fopen (nomefile, “w")) == NULL) { printf ("\nErrore creazione file %s", nomefile); exit (1); }/* visualizza la sequenza di punti sul monitor e la salva nel file */ for (i = 0; i < np; i++) { printf (“\nPunto %3d: %9.4lf,%9.4lf %10.4lf", i+1, punti[i].x, punti[i].y, punti[i].dist); fprintf (output, “\nPunto %3d: %9.4lf,%9.4lf %10.4lf", i+1, punti[i].x, punti[i].y, punti[i].dist); }}

Page 30: 12   Struct

30 © Piero Demichelis

Esempio: punti nel pianovoid bubble (modello punti[ ], int n){ modello provv; /* struttura! */ int ind; boolean ord;

ord = FALSO; while (!ord) { ord = VERO; for (ind = 0; ind < n-1; ind++) if (punti[ind].dist > punti[ind+1].dist)

{ provv = punti[ind];

punti[ind] = punti[ind+1]; punti[ind+1] = provv; ord = FALSO;

} }}