οµές (structures) Στην ενότητα αυτή θα µελετηθούν τα εξής επιµέρους θέµατα: Πίνακες δοµών, δείκτες σε δοµές, και αυτοαναφορικές δοµές. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1
Παράδειγµα Πρόβληµα: Να γράψετε πρόγραµµα το οποίο παίρνει ως όρισµα ένα αρχείο και µετρά τις εµφανίσεις όλων των δεσµευµένων λέξεων της γλώσσας C που περιέχονται στο αρχείο. Το πρόγραµµα θα πρέπει να γνωρίζει τις λέξεις που µας ενδιαφέρει να µετρήσουµε και να διατηρεί για κάθε µια από αυτές ένα µετρητή (µια µεταβλητή τύπου int) όπου να φυλάγεται ο αριθµός των εµφανίσεων της λέξης που έχει παρατηρηθεί άνα πάσα στιγµή κατά τη διάρκεια της εκτέλεσης. Αυτή η συσχέτιση µεταξύ λέξεων - αριθµού εµφανίσεων µπορεί να επιτευχθεί µέσω παράλληλων πινάκων, ή, για καλύτερη οργάνωση, οµαδοποιώντας τα ζεύγη που µας ενδιαφέρουν µέσω µιας δοµής: struct key{ char *word; int count; ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 2
Παράδειγµα (συν.) Εποµένως οι τιµές τύπου struct key που µας ενδιαφέρουν θα διατηρούνται σε ένα πίνακα τύπου struct key, ο οποίος µπορεί να δηλωθεί ως εξωτερική µεταβλητή και να αρχικοποιηθεί ως εξής: struct key keytab[] = { ; auto, 0, break, 0, case, 0, char, 0, const, 0,... unsigned, 0, void, 0, volatile, 0, while, 0 ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 3
οµή πιθανής λύσης: Παράδειγµα (συν.) άνοιξε το αρχείο; while (δεν έχεις φτάσει στο τέλος του αρχείου) if (η επόµενη λέξη είναι µια από τις δεσµευµένες λέξεις της C) αύξησε την τιµή του µετρητή που αντιστοιχεί στη λέξη κατά ένα κλείσε το αρχείο; ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 4
Παράδειγµα (συν.) Θα χρειαστούµε δύο συναρτήσεις: συνάρτηση η οποία θα πρέπει να βρίσκει και να επιστρέφει την επόµενη λέξη του αρχείου που επεξεργαζόµαστε, και µια διαδικασία που θα ψάχνει να βρεί κάθε λέξη του αρχείου στον πίνακα keytab. Υποθέτοντας ότι ο πίνακας είναι ταξινοµηµένος σε αλφαβητική σειρά, µπορούµε να υλοποιήσουµε αυτή τη διαδικασία χρησιµοποιώντας δυαδική αναζήτηση. Έτσι θα ορίσουµε τις συναρτήσεις int getword(char *word, FILE *inp, int lim) η οποία παίρνει σαν παράµετρους (1) ένα πίνακα χαρακτήρων, (2) ένα δείκτη σε αρχείο και (3) ένα ακέραιο, και θα φυλάει την επόµενη λέξη του αρχείου που δείχνεται από το δείκτη inp, (µέχρι lim χαρακτήρες) στον πίνακα word. int binsearch(char *word, struct key tab[], int n) η οποία συκρίνει τη συµβολοσειρά word µε τα πεδία word των πρώτων n στοιχείων του πίνακα tab, και αν η word συµπίπτει µε κάποιο από αυτά τα πεδία µας επιστρέφει τη θέση του στον πίνακα. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 5
Παράδειγµα (συν.) Συνάρτηση main: int main(int argc, char *argv[]) { int n; char word[20]; FILE *inp; if (argc!= 2) { printf("error in the use of the program\n"); exit(1); inp = fopen(argv[argc-1], "r"); ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 6
Παράδειγµα (συν.) while (getword(word, inp, 20)!= EOF) if (isalpha(word[0])) if ((n = binsearch(word, keytab, NKEYS)) >= 0) keytab[n].count++; for (n = 0; n < NKEYS; n++) if (keytab[n].count > 0) printf("%4d %s\n", keytab[n].count, keytab[n].word); fclose(inp); return(0); ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 7
Παράδειγµα (συν.) Η ποσότητα NKEYS είναι ο αριθµός των δεσµευµένων λέξεων στο keytab. Θα µπορούσαµε να υπολογίσουµε την τιµή της απλά µετρώντας τις λέξεις του πίνακα, και να τη δηλώσουµε ως εξωτερική µεταβλητή int ΝΚΕΥS = 10; ιαφορετικά, µπορούµε να χρησιµοποιήσουµε τον τελεστή της C sizeof ο οποίος µας επιστρέφει το µέγεθος οποιουδήποτε αντικειµένου (δηλ. µεταβλητής, πίνακα, δοµής) ή τύπου. Έτσι, για παράδειγµα sizeof(stuct key) sizeof keytab µας επιστρέφουν έναν ακέραιο ίσο µε τα byte που καθορίζουν το µέγεθος της δοµής struct key και του πίνακα keytab, αντίστοιχα. Eποµένως: #define ΝΚΕΥS (sizeof keytab /sizeof(struct key)) ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 8
Παράδειγµα (συν.) int getword(char *word, FILE *inp, int lim){ int c; char *w = word; while (isspace(c = getc(inp))) ; if (c!= EOF) *w++ = c; if (!isalpha(c)){ *w = '\0'; return c; while (--lim > 0){ if (!isalnum(*w = getc(inp))) w++; *w = '\0'; return word[0]; break; ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 9
Παράδειγµα (συν.) Συνάρτηση δυαδικής διερεύνησης: αναζήτηση της λέξης word στον πίνακα τύπου struct key, tab[]. int binsearch(char *word, struct key tab[], int n){ int cond; int low, mid, high; low = 0; high = n 1; while (low <= high){ mid = (high + low) / 2; if ((cond = strcmp(word, tab[mid].word)) < 0) high = mid 1; else if (cond > 0) low = mid + 1; else return mid; return 1 ; ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 10
Άσκηση Να ξαναγράψετε το πρόγραµµα µέτρησης δεσµευµένων λέξεων χρησιµοποιώντας δείκτες διευθύνσεων για αναφορά στα στοιχεία του πίνακα keytab. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 11
Aυτοαναφορικές δοµές struct Employee { char[20] name; int age; struct Employee manager; ; Ποιο είναι το πρόβληµα µε τον πιο πάνω ορισµό δοµής; Εντούτις µπορούµε να ορίσουµε δοµές που αναφέρονται στον εαυτό τους, όπως στην προκειµένη περίπτωση δοµή Employee όπου για κάθε στοιχείο της έχουµε πεδίο που αναφέρεται στον διευθυντή του εργοδοτηµένου, χρησιµοποιώντας δείκτες: struct Employee { char[20] name; int age; struct Employee *manager; ; ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 12
Αυτοαναφορικές δοµές (συν.) Παρόµοια µπορούµε να ορίσουµε παραλλαγή αυτοαναφορικών δοµών όπου δύο δοµές αναφέρονται η µια στην άλλη. Αυτό αντιµετωπίζεται ως εξής: struct s1 {... struct s2 *p;... ; struct s2 {... struct s1 *q;... ; ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 13
typedef H C διαθέτει την typedef για δηµιουργία νέων ονοµάτων τύπων δεδοµένων, π.χ. typedef int Length; typedef char *String; Παρόµοια µπορεί να χρησιµοποιηθεί για να δώσει oνóµατα σε δοµές: typedef struct { char firstname[15]; char lastname[15]; char gender; /* M ή F */ int age; Person;... Person p; p.age = 12;... ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 14