Τκήκα Πιεξνθνξηθήο Παλεπηζηήκην Κύπξνπ ΕΠΛ132 Αξρέο Πξνγξακκαηηζκνύ II Δηάιεμε 8: Δνκέο, Ελώζεηο θαη Απαξηζκεηνί Τύπνη (Κεθάιαην 16, KNK-2ED) Δεκήηξεο Ζεϊλαιηπνύξ http://www.cs.ucy.ac.cy/courses/epl132 8-1
Πεξηερόκελν Δηάιεμεο 8 Δνκέο (Structures) Αλαπαξάζηαζε ζηε Μλήκε, Δειώζεηο & Τύπνη Δνκώλ, Αξρηθνπνίεζε Εκθσιεπκέλεο Δνκέο & Πίλαθεο Δείθηεο ζε Δνκέο, Δνκέο σο νξίζκαηα ζπλαξηήζεσλ θαη ηηκέο επηζηξνθήο Παξαδείγκαηα: Σύγθξηζε, samefamily, addtofamily Δνκέο, sizeof θαη Θέκαηα Επζπγξάκκηζεο Μλήκεο Ελώζεηο (Unions) Αλαπαξάζηαζε ζηε Μλήκε, Δειώζεηο & Αξρηθνπνίεζε Απαξηζκεηνί Τύπνη Δεδνκέλωλ (Enumerations) Αλαπαξάζηαζε ζηε Μλήκε, Δειώζεηο & Αξρηθνπνίεζε 8-2
Δνκέο (Structures) Δνκή είλαη κηα ζπιινγή από κηα ή πεξηζζόηεξεο κεηαβιεηέο, πηζαλώο δηαθνξεηηθώλ ηύπωλ πνπ νκαδνπνηνύληαη κε έλα όλνκα γηα επθνιόηεξν ρεηξηζκό. Οξηζκόο δνκώλ γίλεηαη κε ηε ζύληαμε: struct name { δηλώζεις πεδίων }; Παξάδεηγκα: struct Person { char firstname[15]; char lastname[15]; char gender; /* M ή F */ int age; }; 8-3
Δνκέο (Αλαπαξάζηαζε ζηε Μλήκε) Μηα δνκή αλαπαξηζηάηαη ζε ζπλερόκελεο δηεπζύλζεηο κλήκεο, όπσο θαη νη πίλαθεο. struct { int number; char name[name_len+1]; int on_hand; } part1, part2; To part1, part2 νξίδεη 2 κεηαβιεηέο ηεο ελ ιόγσ δνκήο. 8-4
Δνκέο (Δήισζε & Τύπνη Δνκώλ) Η ιέμε struct εηζάγεη ηε δήισζε κηαο δνκήο. Μπνξεί λα αθνινπζείηαη (πξναηξεηηθά) από θάπνην όλνκα, πνπ απνθαιείηαη ετικέτα δομής θαη νλνκαηίδεη ην είδνο ηεο δνκήο. Π.ρ., struct Person { } Οη κεηαβιεηέο πνπ θαηνλνκάδνληαη κέζα ζηε δνκή νλνκάδνληαη μέλη ή πεδία., π.χ., int age; Μηα δήισζε struct νξίδεη έλα ηύπν. Γηα λα δειώζνπκε κεηαβιεηέο ή πίλαθεο ηύπνπ δνκήο γξάθνπκε: struct Person x; struct Person people[40]; Eλαιιαθηηθά κπνξνύκε επίζεο λα παξαιείςνπκε ην όλνκα ηεο δνκήο αιιά λα πεξηγξάςνπκε ηα κέιε ηεο: struct { char firstname[15]; char lastname[15]; char gender; int age; } x, people[40]; 8-5
Δνκέο (Δήισζε & Τύπνη Δνκώλ) struct { char firstname[15]; char lastname[15]; char gender; int age; } x, people[40]; Ίδιο με struct person { char firstname[15]; char lastname[15]; char gender; int age; }; struct person x, people[40]; Σπληζηώκελνο ηξόπνο Δήιωζεο Δνκήο θαη Οξηζκνύ Δνκήο γηα ην ΕΠΛ132 char firstname[15]; char lastname[15]; char gender; int age; } PERSON; PERSON x, people[40]; και typedef struct person PERSON; PERSON x, people[40]; 8-6
Δνκέο (Αξρηθνπνίεζε) Αξρηθνπνίεζε κηαο κεηαβιεηήο ή πίλαθα ηύπνπ δνκήο γίλεηαη απνδίδνληαο ηηκέο ζηα κέιε σο εμήο: struct Person x = {"Aνδρέας", "Ανδρέοσ", 'M', 43}; struct Person people[] = {"Aνδρέας", "Ανδρέοσ", 'M', 43, "Μαρία", "Γεωργίοσ", 'F', 38, "Χρίζηος", "Χαραλάμποσς", 'Μ', 14 }; ή (θαιύηεξα) struct Person people[] = {{"Aνδρέας", "Ανδρέοσ", 'M', 43}, {"Μαρία", "Γεωργίοσ", 'F', 38}, { "Χρίζηος", "Χαραλάμποσς", 'Μ', 14}}; Αλαθνξά ζε κέινο κηαο δνκήο γίλεηαη κέζσ ηεο θαηαζθεπήο: όνομα_δομής.μέλος π.ρ., scanf("%d", &x.age); if (x.age > 40) printf("age: %d \n", x.age); 8-7
Εκθσιεπκέλεο Δνκέο (Nested Structures) Δνκέο κπνξεί λα είλαη αιιειέλδεηεο, δειαδή λα θωιηάδνληαο (εκθωιεύνληαη) ε κηα κέζα ζηελ άιιε, δεκηνπξγώληαο πην πνιύπινθεο δνκέο: struct Person { char firstname[15]; int age; }; struct family { struct Person father; struct Person mother; int numofchild; struct Person children[5]; }; int main(void){ struct Person x, y, z; struct family fml; fml.numofchild = 2; strcpy(fml.father.firstname, "Joe"); strcpy(fml.children[0].firstname, "Mary"); ή (θαιύηεξα) char firstname[15]; int age; } PERSON; PERSON father; PERSON mother; int numofchildren; PERSON children[5]; } FAMILY; int main(void){ PERSON x, y, z; FAMILY fml; fml.numofchildren = 2; strcpy(fml.father.firstname, "Joe"); strcpy(fml.children[0].firstname, "Mary"); 8-8
Εκθσιεπκέλεο Δνκέο (Nested Structures) char firstname[15]; char lastname[15]; char gender; int age; } PERSON; char title[30]; int salary; PERSON employee; } POSITION; int main(void) { POSITION programmer, secretaries[10]; strcpy(programmer.title, "Software Engineer"); programmer.salary = 2500; /*per month */ strcpy(programmer.employee.firstname, "Joe"); strcpy(programmer.employee.lastname, "Hacker");... strcpy(secretaries[0].employee.firstname, "Jane"); } 8-9
Δνκέο θαη Σπλαξηήζεηο (Structures and Functions) Επηηξεπηέο πξάμεηο ζε κηα δνκή είλαη: ε αληηγξαθή ηεο, ε απόδνζε ηηκήο ζ απηήλ ζαλ ζύλνιν, ε εμαγωγή ηεο δηεύζπλζήο ηεο, θαη ε πξνζπέιαζε ησλ κειώλ ηεο. Μεηαβιεηέο ηύπνπ δνκήο κπνξνύλ λα πεξαζηνύλ σο νξίζκαηα ζε ζπλαξηήζεηο όπσο επίζεο θαη λα επηζηξαθνύλ ωο απνηειέζκαηα ζπλαξηήζεωλ Παξάδεηγκα: Person inc_age (Person x){ x.age += 1; return x; } Person x1, x2; x2 = inc_age(x1); Πέξαζκα δηα ηηκήο! (ην x αληηγξάθεηαη κέζα ζηε ζπλάξηεζε) (αξγόηεξα ζα δνύκε πσο πεξληνύληαη δνκέο δηα δηεύζπλζεο) 8-10
Άζθεζε 1 Δνκέο ΔΕΝ κπνξνύλ λα ζπγθξηζνύλ: π.ρ. ε έθθξαζε x1 == x2 ΔΕΝ είλαη έγθπξε. Άζθεζε 1: Να γξάςεηε ζπλάξηεζε ε νπνία παίξλεη δύν παξακέηξνπο ηύπνπ struct Person θαη ηηο ζπγθξίλεη επηζηξέθνληαο TRUE εάλ είλαη ηα ίδηα άηνκα. 8-11
Άζθεζε 1 /* Εργαζία 1 */ #define NAMESIZE 15 char firstname[namesize]; char lastname[namesize]; char gender; int age; } PERSON; int sameperson(person, PERSON); // function prototype int sameperson(person x, PERSON y) { return( (strcmp(x.firstname, y.firstname) == 0) && (strcmp(x.lastname, y.lastname) == 0) && (x.gender == y.gender) && (x.age == y.age)); } int main() { PERSON per1 = {"Marios", "Michael", 'M', 24}; PERSON per2 = {"Antonis", "Charalambous", 'M', 22}; if (sameperson(per1,per1)) printf("same Persons"); else printf("different Persons"); return 0; } 8-12
Δείθηεο ζε Δνκέο (Pointer to Structures) Μπνξνύκε επίζεο λα ρξεζηκνπνηήζνπκε δείθηεο ζε δνκέο. Δείθηεο ζε Δνκή παξάδεηγκα δήιωζεο: struct Person p, *pp; ή PERSON p, *pp; ε κεηαβιεηή pp είλαη δείθηεο πξνο κηα δνκή ηύπνπ Person. Έηζη κπνξνύκε λα γξάςνπκε pp = &p; printf("%s", (*pp).firstname); óπνπ *pp είλαη ε δνκή πνπ δείρλεηαη από ηνλ δείθηε, ελώ (*pp).firstname είλαη ην πξώην πεδίν ηεο δνκήο. Πξνζνρή: ε πξνηεξαηόηεηα ηνπ ηειεζηή κέινπο δνκήο, '.', είλαη μεγαλύτερη από απηή ηνπ ηειεζηή έκκεζεο αλαθνξάο, '*'. Επνκέλσο νη παξελζέζεηο ζην (*pp).firstname είλαη απαξαίηεηεο. 8-13
Δείθηεο ζε Δνκέο & Σπλαξηήζεηο (Pointer to Structures) Δείθηεο γηα δνκέο ρξεζηκνπνηνύληαη ηόζν ζπρλά πνπ παξέρεηαη ν πην θάησ ελαιιαθηηθόο ζπκβνιηζκόο σο ζπληνκνγξαθία: (*p).μέλος_δομής = p->μέλος_δομής Πέξαζκα Παξακέηξωλ Δηα Αλαθνξάο: Σε πεξίπησζε πνπ ζέινπκε κία ζπλάξηεζε λα αιιάμεη ηα πεξηερόκελα κίαο δνκήο, πεξλάκε σο παξάκεηξν ζηε ζπλάξηεζε ην δείθηε ηεο δνκήο απηήο όπσο αθξηβώο εξγαδόκαζηαλ θαη ζε άιιεο δνκέο δεδνκέλσλ, π.ρ., : struct Person p;... initperson(&p); /* Κλήζη ζσνάρηηζης */... void initperson(struct Person *p){ strcpy( p->firstname, "Aνδρέας"); strcpy( p->lastname, "Ανδρέοσ"); p->gender = 'M'; p->age = 43; } 8-14
Άζθεζε 2 Άζθεζε 2: Να γξάςεηε ζπλάξηεζε ε νπνία παίξλεη σο δεδνκέλν εηζόδνπ κηα νηθνγέλεηα (ηύπνπ struct Family) θαη έλα άηνκν (ηύπνπ struct Person), θαη αλ ην άηνκν δελ αλήθεη ήδε ζηα παηδηά ηεο νηθνγέλεηαο ηόηε ην πξνζζέηεη. #include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #define NAMESIZE 15 #define CHILDSIZE 5 char firstname[namesize]; char lastname[namesize]; char gender; int age; } PERSON; PERSON father; PERSON mother; int numofchildren; PERSON children[childsize]; } FAMILY; 8-15
Άζθεζε 2 int main() { FAMILY fml; PERSON per1 = {"Marios", "Michael", 'M', 24}; fml.numofchildren = 0; addtofamily(&fml,per1); } int addtofamily(family *fml, PERSON per) { bool family_member = false; // find if x belongs to family for (int i=0; i<fml->numofchildren; i++) { if ((strcmp(fml->children[i].firstname, per.firstname) == 0) && (strcmp(fml->children[i].lastname, per.lastname) == 0) && (fml->children[i].gender == per.gender) && (fml->children[i].age == per.age) ) family_member = true; } if (family_member) { // First Failure Condition printf("already Family Member!"); return EXIT_FAILURE; } if (fml->numofchildren == CHILDSIZE) { // Second Failure Condition printf("children Array is full!"); return EXIT_FAILURE; } } strcpy(fml->children[fml->numofchildren].firstname, per.firstname); strcpy(fml->children[fml->numofchildren].lastname, per.lastname); fml->children[fml->numofchildren].gender = per.gender; fml->children[fml->numofchildren].age = per.age; (fml->numofchildren)++; return EXIT_SUCCESS; 8-16
Δνκέο, sizeof θαη Θέκαηα Επζπγξάκκηζεο Μλήκεο Τν Πξόβιεκα int ID; char state[3]; int salary; } EMPLOYEE; // 4Β // 3Β // 4Β sizeof(employee)=12 αληί 11 ζε κία 4-byte aligned κλήκε! Απηό ζπκβαίλεη επεηδή ηα δεδνκέλα είλαη επζπγξακκηζκέλα ζε 4B θαη ην state έρεη 1 byte padding Γξεγνξόηεξε Πξόζβαζε ζηα δεδνκέλα (πξνηηκεηέα κέζνδνο) αιιά Σπαηαιείηαη Μλήκε 8-17
Δνκέο, sizeof θαη Θέκαηα Επζπγξάκκηζεο Μλήκεο Επζπγξάκκηζε Μλήκεο (Memory Alignment): Ο κεηαγιωηηηζηήο πξνζζέηεη padding (θελά bytes) ζε δνκέο γηα λα βξίζθνληαη ζε δηεπζύλζεηο πνιιαπιάζηεο κηαο βαζηθήο κνλάδαο, π.ρ., 2b,4b,8b To padding δελ είλαη νξαηό ζε κεηαβιεηέο, νύηε θαη καο ελνριεί αιιά θαηαιακβάλεη ρώξν! Ο ιόγνο ύπαξμεο ηνπ είλαη όηη επηηξέπεη ζην Λ.Σ. λα αλαθηά γξεγνξόηεξα δεδνκέλα από ηελ κλήκε (π.ρ., 4 bytes αλά θύθιν αληί 1 byte αλά θύθιν) Ωζηόζν απαηηεί ρώξν πνπ κπνξεί λα ΜΗΝ ππάξρεη π.ρ., ζε πεξίπησζεο όπνπ ε κλήκε είλαη πνιύ πεξηνξηζκέλε (π.ρ., ζε κηθξνεπεμεξγαζηέο) ή εάλ ζέινπκε λα ρωξέζνπκε πνιιά δεδνκέλα ζηε κλήκε, (π.ρ., έλα κεγάιν επξεηήξην) 8-18
Δνκέο, sizeof θαη Θέκαηα Παξάδεηγκα int ID; Επζπγξάκκηζεο Μλήκεο char state[3]; int salery; Όξηζκα ηνπ GCC κόλν // 4Β // 3Β // 4Β } attribute (( packed )) EMPLOYEE; sizeof(employee) επηζηξέθεη 11 ζε κηα 4-byte aligned κλήκε! Απηό ζπκβαίλεη επεηδή ηα δεδνκέλα γίλνληαη pack (ζπκπηύζζνληαη) ρσξίο επηπξόζζεην padding Αξγόηεξε Πξόζβαζε αιιά Δελ Σπαηαιείηαη Μλήκε (ρξεζηκνπνηείηαη όηαλ καο ελδηαθέξεη ν ρώξνο!) Πεξηζζόηεξα: http://gcc.gnu.org/onlinedocs/gcc/type-attributes.html 8-19
Ελώζεηο (Unions) Μηα έλωζε (union), απνηειείηαη από έλα ή πεξηζζόηεξα πεδία, κε ελδερνκέλσο δηαθνξεηηθό ηύπν, αιιά θαηαιακβάλεη ρώξν ίζν κόλν κε ην κεγαιύηεξν πεδίν. struct { int i; double d; } s; union { int i; double d; } u; Η βαζηθή δηαθνξά κε ηε δνκή, είλαη όηη ν κεηαγισηηηζηήο δεζκεύεη αξθεηό ρώξν κόλν γηα ην κεγαιύηεξν από ηα πεδία. Σπλεπώο κηα έλσζε απνζεθεύεη αλά πάζα ζηηγκή ΜΟΝΟ έλα από ηα πεδία. Ο πξνγξακκαηηζηήο (κέζσ επηπιένλ κεηαβιεηήο) πξέπεη λα ζπκάηαη πνην. Εάλ αιιάμεη ην u.i ράλεηαη ην u.d θαη αληίζηξνθα 8-20
#define INT_TYPE 1 #define REAL_TYPE 2 struct item { int type; union { int ival; double dval; } info; Ελώζεηο (Παξάδεηγκα) Σεκαία (flag) πνπ ρξεζηκνπνηείηαη γηα λα ζπκάηαη ην πξόγξακκα ηη έρεη απνζεθεπηεί κέζα ζην union. } struct item x; if (x.type == INT_TYPE) printf("value of info = %d\n, x.info.ival); if (x.type == REAL_TYPE) printf("value of info = %lf\n", x.info.dval); 8-21
Ελώζεηο (Unions) Εθαξκνγέο: Γηα εμνηθνλόκεζε κλήκεο αιιά θπξίσο γηα δεκηνπξγία αλάκεηθησλ δνκώλ δεδνκέλσλ Παξάδεηγκα ελόο Page ην νπνίν θαηά ηελ εθηέιεζε κπνξεί λα ζπκπεξηθέξεηαη σο RootPage, DirectoryPage, IndexPage ή DataPage (ειεγρόκελν από πεδίν typ) short typ; short crc; short pwc; char siz; int ppa; union { RootP rootp; DirP dirp; DataP datap; IdxP idxp; }; } attribute ((packed)) Page ; DataRec records[drec]; } attribute ((packed)) DataP ; long ts; int val1; } attribute ((packed)) DataRec; long lastts; IdxRec records[irec]; } attribute ((packed)) IdxP ; 8-22
Απαξηζκεηνί Τύπνη (Enumerations) Απαξηζκεηόο Τύπνο (Enumeration): νξίδεη κεηαβιεηέο ησλ νπνίσλ ε ηηκή κπνξεί λα νξίδεηαη, κεηαμύ άιισλ, από έλα πξνζδηνξηζκέλν ζύλνιν ζηαζεξώλ Π.ρ., είδνο θάξηαο πνπ επέιεμε ν ρξήζηεο typedef enum {CLUBS, DIAMONDS, HEARTS, SPADES} CARD; CARD s = CLUBS; /* s είναι ηώρα 0 (CLUBS) CARD s = 10; /* # OK, αλλά επικίνδσνο */ Παξαηεξήζεηο Όκνηα ζύληαμε κε struct θαη union Tν s είλαη ζηελ νπζία κεηαβιεηή αθέξαηνπ ηύπνπ θαη ηα CLUBS, DIAMONDS, HEARTS, θαη SPADES είλαη ζπκβνιηθά νλόκαηα γηα ηηο αθέξαηεο ηηκέο 0, 1, 2, θαη 3. 8-23
#include <stdio.h> typedef enum { CLUBS, DIAMONDS, HEARTS, SPADES } CARD; Απαξηζκεηνί Τύπνη (Παξάδεηγκα) int main(void) { CARD s; s = CLUBS; /* s = 0 (CLUBS) */ printf("%d\n", s); } Οξηζκόο "ζηαζεξώλ" ελόο απαξηζκεηνύ ηύπνπ Πιενλεθηήκαηα: a) Δε ρξεηάδεηαη λα δώζνπκε 4 μερσξηζηά define b) Δειώλνπκε ξεηά (ζηνλ πξνγξακκαηηζηή) όηη ην CARD ζα πξέπεη λα παίξλεη κόλν απηέο ηηο 4 ηηκέο (0-3), εάλ θαη δελ απηό δελ ειέγρεηαη από ηνλ κεηαγισηηηζηή. s++; /* s = 1 (DIAMONDS)*/ printf("%d\n", s); s = SPADES; /* s = 3 (SPADES)*/ printf("%d\n", s); return 0; Σύνθεζη Enum με struct & union enum {IKIND, DKIND} kind; union { int i; double d; } u; } Number; 8-24