Record in C: il costruttore struct. Le variabili di tipo record e i nuovi tipi record si dichiarano in C tramite il costruttore di tipo struct:. <var-record> ::= <costr-struct> <identif> ; <costr-struct> ::= <seq-campi>} <seq-campi> ::= <seq-campi-omog> <seq-campi-omog> ; <seq-campi> <seq-campi-omog> ::= <tipo> <seq-nomi-campi> <seq-nomi-campi> ::= <identif> <identif>, <seq-nomi-campi> int Giorno; int Anno; } Data; /* variabile Data come record di tre campi: Giorno Mese e Anno, tutti di tipo intero */ Data Data.Giorno Data.Mese Data.Anno 15 10 1919 /* DICHIARAZIONE ALTERNATIVA : */ int Giorno, Mese, Anno; } Data; 1
Inizializzazione di una variabile record int Giorno, Mese, Anno; } Data = {15,10,1919}; è possibile accedere ad una variabile di tipo record nel suo insieme, come se fosse una variabile semplice oppure campo per campo, rispettando tutte le regole previste per il tipo associato a ciascun campo. int Giorno, Mese, Anno; } DataEsame; int Giorno, Mese, Anno; } DataOrale; /* accesso alle variabili campo per campo */ DataOrale.Anno = DataEsame.Anno; DataOrale.Mese = DataEsame.Mese; DataOrale.Giorno= DataEsame.Giorno + 1; /* accesso alle variabili nel loro insieme */ DataOrale = DataEsame; 2
int Matr; char Sesso; int Età; } Stud; /* variabile Stud */ Stud.Mat Stud.Sess Stud.Et Stu r o à d 15 'F' 20 Modifichiamo Stud, aggiungendo un campo Nome come una stringa int Matr; char Nome[21]; char Sesso; int Età; } Stud; /* variabile Stud */ Stud.Mat Stud.Nom Stud.Sess Stud.Et Stu r e o à d 15 "Paola" 'F' 20 Questo è un primo esempio in cui un tipo strutturato (Nome di tipo stringa) è usato all interno di un altro tipo strutturato (Stud di tipo record) : composizione di tipi strutturati. una variabile di tipo record deve essere letta da input campo per campo, rispettando tutte le regole previste per il tipo associato a ciascun campo: printf("inserire Matricola Studente "); scanf("%d",&stud.matr); printf("inserire Nome Studente "); scanf("%20s", Stud.Nome); Il campo Nome di Stud è una stringa, quindi non ci vuole &! 3
COMPOSIZIONE DI TIPI STRUTTURATI Modifichiamo Stud, aggiungendo un campo DataDiNascita come record int Matr; char Nome[21]; int Giorno; char Sesso; int Età; } Stud; /* variabile Stud */ printf("inserire Data di Nascita dello Studente \n"); printf("giorno : "); scanf("%d",&stud.datadinascita.giorno); printf("mese : "); scanf("%d",&stud.datadinascita.mese); printf("anno : "); scanf("%d",&stud.datadinascita.anno); è possibile utilizzare come componenti dei tipi strutturati, costruendo così delle matrici di record, dei record di matrici, 1 Corso MaxStud Nome Parola DataDiNascita 1 NumCar Data Giorno Mese Anno char Nome[NumCar]; struct{int Giorno; } Corso[MaxStud]; 4
NOTA Consideriamo le seguenti dichiarazioni int Giorno, Mese, Anno; } DataEsame; int Giorno, Mese, Anno; } DataOrale; Non tutti i compilatori (compreso DEV-C++) accettano l assegnamento DataOrale=DataEsame; in quanto i tipi delle due variabili sono considerati incompatibili. Se invece viene utilizzata la seguente dichiarazione: int Giorno, Mese, Anno; } DataEsame,DataOrale; Allora l assegnamento DataOrale=DataEsame; viene considerato corretto! Nello stesso modo, se considero char Nome[NumCar]; struct{ int Giorno; } Corso[MaxStud]; char Nome[NumCar]; struct{ int Giorno; } MAX; Non tutti i compilatori (compreso DEV-C++) accettano l assegnamento MAX=Corso[0]; In questo caso si dovrebbe effettuare char Nome[NumCar]; struct{ int Giorno; } MAX, Corso[MaxStud]; Allora l assegnamento MAX=Corso[0]; viene considerato corretto. Questi problemi non si presentano con l uso del typedef. 5
Quando lo stesso tipo strutturato (array o record) deve essere usato in più di una dichiarazione di variabili, è bene dichiarare tale tipo esplicitamente con typedef: Ad esempio, nel caso di char Nome[NumCar]; struct{ int Giorno; } MAX, Corso[MaxStud]; si usa due volte lo stesso tipo strutturato, sia per dichiarare MAX che per Corso. Allora si definisce esplicitamente tale tipo tramite typedef: typedef char Nome[NumCar]; struct{int Giorno; } TipoStudente; e il nuovo tipo TipoStudente è quindi usato per dichiarare le due variabili: TipoStudente MAX; TipoStudente Corso[MaxStud]; In questo modo l assegnamento MAX=Corso[0]; viene considerato corretto. Nel seguito viene riportato l esempio completo Studente più giovane, ovvero studente con Data di Nascita maggiore utilizzando typedef. #include <stdio.h> #define NumCar 25 #define MaxStud 4 main(){ typedef char Nome[NumCar]; struct{ int G; int M; int A; } DataDiNascita; } TipoStudente; TipoStudente MAX; TipoStudente Corso[MaxStud]; int I; 6
/* lettura degli studenti */ for(i=0;i<maxstud;i++){ printf("inserire studente n. %d\n",i); printf("nome : "); scanf("%20s",corso[i].nome); printf("data di Nascita \n "); printf("giorno : "); scanf("%d",&corso[i].datadinascita.g); printf("mese : "); scanf("%d",&corso[i].datadinascita.m); printf("anno : "); scanf("%d",&corso[i].datadinascita.a); } /* stampa degli studenti inseriti */ printf("\n\n stampa degli studenti inseriti \n\n"); for(i=0;i<maxstud;i++){ printf("\nstudente n. %d\n",i); printf("nome = %-20s",Corso[I].Nome); printf("nato il %d-%d-%d: \n",corso[i].datadinascita.g, Corso[I].DataDiNascita.M,Corso[I].DataDiNascita.A); } /* Calcolo del MAX. cioe studente con DataDiNascita piu' grande*/ MAX=Corso[0]; for(i=1;i<maxstud;i++) if(corso[i].datadinascita.a > MAX.DataDiNascita.A Corso[I].DataDiNascita.A == MAX.DataDiNascita.A && Corso[I].DataDiNascita.M > MAX.DataDiNascita.M Corso[I].DataDiNascita.A==MAX.DataDiNascita.A && Corso[I].DataDiNascita.M == MAX.DataDiNascita.M && Corso[I].DataDiNascita.G > MAX.DataDiNascita.G ) MAX=Corso[I]; printf("\nlo studente piu' giovane e' \n"); printf("nome = %-20s",MAX.Nome); printf("nato il %d-%d-%d: \n",max.datadinascita.g, MAX.DataDiNascita.M,MAX.DataDiNascita.A); } Ovviamente il precedente programma è corretto se c e un solo studente con la massima DataDiNascita. Per considerare il caso in cui ci siano più studenti con la stessa data di nascita e quindi la possibilità di avere due o più studenti con la massima DataDiNascita, dopo aver caalcolato MAX, si scandisce di nuovo Corso e si stampano tutti gli studenti la cui data di nascita è quella di MAX. 7
Si noti che per controllare l uguaglianza di due record (in questo caso le due date) non possiamo confrontare i due record con == ma si deve usare il confronto elemento per elemento: infatti l operatore == si applica solo ai tipi semplici. In altre parole, è sbagliato scrivere if(corso[i].datadinascita == MAX.DataDiNascita) ma si deve scrivere if(corso[i].datadinascita.a == MAX.DataDiNascita.A && Corso[I].DataDiNascita.M == MAX.DataDiNascita.M && Corso[I].DataDiNascita.G == MAX.DataDiNascita.G ) Riportiamo il ciclo for che ci consente di stampare tutti gli studenti più giovani for(i=0;i<maxstud;i++) if( Corso[I].DataDiNascita.A == MAX.DataDiNascita.A && Corso[I].DataDiNascita.M == MAX.DataDiNascita.M && Corso[I].DataDiNascita.G == MAX.DataDiNascita.G ) { printf("\n Nome = %-20s",Corso[I].Nome); printf("nato il %d-%d-%d: \n", Corso[I].DataDiNascita.G, Corso[I].DataDiNascita.M, Corso[I].DataDiNascita.A); } 8