Upload
sheera
View
48
Download
4
Embed Size (px)
DESCRIPTION
Δομές στην C ( επανάληψη ). Γλώσσα C & Unix Τμήμα Πληροφορικής, ΑΠΘ B’ εξάμηνο. lpis . csd . auth . gr / curriculum / C + Unix / UNCL 202. html. Σύνθετοι Τύποι Δεδομένων. structure (δομή): ομαδοποίηση πολλών μεταβλητών κάτω από ένα κοινό όνομα Π.χ. εγγραφή αρχείου - PowerPoint PPT Presentation
Citation preview
Δομές στην C (επανάληψη)
Γλώσσα C & UnixΤμήμα Πληροφορικής, ΑΠΘB’ εξάμηνο
lpis.csd.auth.gr/curriculum/C+Unix/UNCL202.html
2
Σύνθετοι Τύποι Δεδομένων
structure (δομή): ομαδοποίηση πολλών μεταβλητών κάτω από ένα κοινό όνομα Π.χ. εγγραφή αρχείου Π.χ. γραμμή σε βάση δεδομένων
union (ένωση): επιτρέπει το ίδιο μέρος της μνήμης να οριστεί ως δύο ή παραπάνω διαφορετικούς τύπους μεταβλητών
enumeration (απαρίθμηση): λίστα συμβόλων
typedef: δημιουργία νέων ονομάτων τύπων δεδομένων
3
Δομή (structure)
Ομαδοποίηση πολλών μεταβλητών κάτω από ένα κοινό όνομα Κρατιούνται μαζί τα δεδομένα που σχετίζονται
μεταξύ τους Η δήλωση μιας δομής ορίζει ένα πρότυπο
Μπορεί να χρησιμοποιηθεί για τη δημιουργία μεταβλητών αυτού του προτύπου
Οι μεταβλητές που απαρτίζουν μια δομή λέγονται στοιχεία ή μέλη (members) της δομής Όλα τα στοιχεία μιας δομής πρέπει να σχετίζονται
λογικά μεταξύ τους Π.χ. όνομα, επώνυμο και διεύθυνση ενός ατόμου
4
Δήλωση Δομής
Δομή για την αναπαράσταση των στοιχείων ενός μαθητή
struct mathitis { char onoma[15]; char eponymo[25]; short int apousies; short int vathmos;
}; Πληροφορεί τον μεταγλωττιστή της C ότι ξεκινά η δήλωση μιας δομής (ή μιας μεταβλητής δομής).
Όνομα της δομής
Δηλώσεις στοιχείων
5
Χρήση Δομής
Ακόμα δεν έχει δημιουργηθεί καμία μεταβλητή
Το mathitis είναι ένας καινούριος τύπος δεδομένων
Μπορεί να χρησιμοποιηθεί για τη δήλωση μεταβλητών αυτού του τύπου
struct mathitis x1;
6
Ταυτόχρονη Δήλωση και Χρήση Δομής
Μπορούμε να δηλώσουμε μεταβλητές ταυτόχρονα με τη δήλωση μιας δομής
struct mathitis {
char onoma[15];
char eponymo[25];
unsigned short int apousies;
unsigned short int vathmos;
} x1, x2, x3;
7
Ανώνυμες Δομές Όταν δηλώνουμε μεταβλητές μαζί με
τη δομή μπορούμε να μη δώσουμε όνομα στη δομή Όταν δεν πρόκειται να δηλώσουμε
επιπλέον μεταβλητές αυτού του τύπου
struct { char onoma[15]; char eponymo[25]; unsigned short int apousies; unsigned short int vathmos;} x1, x2, x3;
8
Προσπέλαση Στοιχείων Δομής
Τα στοιχεία μιας μεταβλητής δομής, μπορούν να προσπελαστούν με τον τελεστή τελεία “.”
Γενική μορφή:struct_var_name.member_name
Παράδειγμα: x1.apousies = 2;
printf("%d", x1.apousies);
9
Σύνθετες Δομές
struct mathitis { char onoma[15]; ...
struct date birthday;} x1;struct date {
int day;int month;int year;
};
•Πρόσβαση στοιχείων «εσωτερικής» δομής
x1.birthday.year;
10
Πίνακες από Δομές
Η πιο συνηθισμένη χρήση των δομών, είναι σε πίνακες πολλών μεταβλητών δομής
Για να δηλωθεί ένας πίνακας από δομές, πρέπει να δηλωθούν: η δομή, και μετά ένας πίνακας από αυτές τις δομές
Παράδειγμα:struct mathitis m[100];
11
Πίνακες από Δομές – Προσπέλαση Στοιχείων
Για να προσπελαστεί ένα στοιχείο μέσα στον πίνακα πρέπει να χρησιμοποιηθεί ο αύξων
αριθμός του στοιχείου στον πίνακα
Π.χ. εκτύπωση ονόματος του τρίτου μαθητή:
printf("%s", m[2].onoma);
12
Δομές και Συναρτήσεις
Πέρασμα μεμονωμένου στοιχείου δομής ως παράμετρο σε συνάρτηση
Πέρασμα ολόκληρης δομής Κλήση με τιμή
Πέρασμα διεύθυνσης μνήμης δομής Κλήση με αναφορά
13
Στοιχεία Δομής ως Παράμετροι Συναρτήσεων
Οι μεταβλητές που αποτελούν τα στοιχεία μιας δομής μπορούν να δοθούν σε μια συνάρτηση ως τιμές ως δείκτες προς τη διεύθυνση τους
Παράδειγμα δομής:struct paradeigma { char c; int i; float f; char s[10];} x;
14
Παραδείγματα Κλήσης με Τιμή
func_v1(x.c);
func_v2(x.i);
func_v3(x.f);
func_v4(x.s[2]);
struct paradeigma { char c; int i; float f; char s[10];} x;
15
Παραδείγματα Κλήσης με Αναφορά
func_r1(&x.c);func_r2(&x.i);func_r3(&x.f);
struct paradeigma { char c; int i; float f; char s[10];} x;
ο τελεστής διεύθυνσης & τοποθετείται πριν από το όνομα της μεταβλητής δομής
όχι πριν από την μεταβλητή του στοιχείου της δομής
16
Παραδείγματα Κλήσης με Αναφορά
func_r4(x.s);
struct paradeigma { char c; int i; float f; char s[10];} x;
Επειδή το όνομα ενός πίνακα χαρακτήρων είναι η διεύθυνση του πρώτου στοιχείου του πίνακα, παραλείπουμε τελείως τον τελεστή &
17
Παραδείγματα Κλήσης με Αναφορά
func_r5(&x.s[2]);
struct paradeigma { char c; int i; float f; char s[10];} x;
Όταν θέλουμε να δώσουμε τη διεύθυνση κάποιου συγκεκριμένου στοιχείου του πίνακα (εκτός του πρώτου) τότε πρέπει να χρησιμοποιήσουμε τον τελεστή &
18
Παραδείγματα Κλήσης με Αναφορά
func_r5((x.s)+2);
struct paradeigma { char c; int i; float f; char s[10];} x;
Εναλλακτικά θα μπορούσε να είχε χρησιμοποιηθεί αριθμητική δεικτών
19
Κλήση Συνάρτησης με Τιμή μιας Ολόκληρης Δομής
Όταν μια μεταβλητή δομής δίνεται ως παράμετρος σε μια συνάρτηση, τότε γίνεται μια τυπική κλήση της συνάρτησης με τιμή.
Οποιεσδήποτε αλλαγές γίνουν στα στοιχεία της μεταβλητής δομής μέσα στην συνάρτηση, δεν θα είναι μόνιμες.
20
Κλήση Συνάρτησης με Τιμή μιας Ολόκληρης Δομής
Ο τύπος της τυπικής παραμέτρου της συνάρτησης πρέπει να είναι ίδιος με τον τύπο της μεταβλητής-παραμέτρου
Η δομή πρέπει να δηλωθεί ως καθολικός τύπος δεδομένων
Το όνομα της δομής πρέπει να χρησιμοποιηθεί για τη δήλωση των τοπικών μεταβλητών δομής τυπικών παραμέτρων των συναρτήσεων
21
Κλήση Συνάρτησης με Τιμή μιας Ολόκληρης Δομής - Παράδειγμα
#include <stdio.h>
struct test { int a, b; char ch;};
void main(void) { struct test x1; x1.a = 1000; f1(x1);}
void f1(struct test p) { printf("%d", p.a);}
Καθολικός τύπος δεδομένων
22
Κλήση Συνάρτησης με Αναφορά σε μία Ολόκληρη Δομή
Μπορούμε να περνάμε τη διεύθυνση μνήμης μιας μεταβλητής δομής ως παράμετρο σε συνάρτηση
Μπορούμε να κάνουμε μόνιμες αλλαγές στα στοιχεία της μεταβλητής δομής μέσα στη συνάρτηση Δίνοντας τη διεύθυνση της μεταβλητής
δομής στη μνήμη έχουμε κλήση της συνάρτησης με αναφοράΠ
λεο
νέκτη
μα
23
Κλήση Συνάρτησης με Αναφορά σε μία Ολόκληρη Δομή
Η εκτέλεση της συνάρτησης
επιταχύνεται δραστικάΔεν δημιουργείται αντίγραφο της
μεταβλητής δομής στη μνήμη για
χρήση μόνο μέσα στην συνάρτηση
Έχουμε απευθείας προσπέλαση
στη μνήμη
Πλεο
νέκτη
μα
24
Δήλωση Δείκτη σε Δομή
Γενική μορφή:
struct onoma_domis *onoma_deikti Θα πρέπει να έχει προηγηθεί η δήλωση
του structure με όνομα onoma_domis Υπάρχουν κάποια σημεία
διαφοροποίησης από τους υπόλοιπους δείκτες
25
Χρήση Δείκτη σε Δομή
struct mathitis { char onoma[15]; char eponymo[25]; unsigned short int apousies; unsigned short int vathmos;};
void main(void){ struct mathitis x, *p;
p = &x;}
26
Τελεστής Βέλος (->)
Δεν μπορεί να χρησιμοποιηθεί ο τελεστής τελεία (.) για προσπέλαση των στοιχείων της δομής
Πρέπει να χρησιμοποιηθεί ένας καινούργιος τελεστής, ο τελεστής βέλος (->)
Π.χ. για προσπέλαση του στοιχείου apousies μέσω του δείκτη p:
p->apousies = 2;
27
Εναλλακτική Προσπέλαση Στοιχείου Δομής από Δείκτη
Ένας πιο δύσχρηστος τρόπος για προσπέλαση ενός στοιχείου μιας δομής, μέσω του τελεστή τελεία:
(*p).apousies = 2;
p->apousies = 2;
Η χρήση των παρενθέσεων είναι απαραίτητη λόγω χαμηλότερης προτεραιότητας του τελεστή *
28
Συναρτήσεις που Επιστρέφουν Δομές
struct mathitis make_student(char *first, char *last) {
struct mathitis temp;
strcpy(temp.onoma,first);strcpy(temp.eponymo,last);temp.apousies=0;temp.vathmos=0;return temp;
}
29
Συναρτήσεις που Επιστρέφουν Δομές
void main(void){
struct mathitis x;
char first[]=“John”;char last[]=“Smith”;
x = make_student(first,last);}
Επιτρέπεται η ανάθεση τιμής σε ολόκληρη τη δομή (αντιγραφή)
Δεν επιτρέπεται σύγκριση δομών
30
Εφαρμογή – Μέτρηση Συχνότητας Εμφάνισης Λέξεων σε Κείμενο
Έχουμε ένα μεγάλο κείμενο και ψάχνουμε μέσα σε αυτό να βρούμε πόσες φορές εμφανίζονται συγκεκριμένες λέξεις-κλειδιά
Χρειαζόμαστε 2 πίνακες Για την αποθήκευση των λέξεων-κλειδιών
char *keyword[NKEYS]; Για την αποθήκευση της συχνότητας
εμφάνισης της κάθε λέξης
int keycount[NKEYS];
31
Χρήση Πίνακα Δομών
Υπάρχει 1-1 αντιστοιχία μεταξύ των 2 πινάκων, το πιο «κομψό» θα ήταν να χρησιμοποιηθεί 1 πίνακας δομών
struct key { char *word;
int count;
};
struct key keytab[NKEYS];
32
Αρχικοποίηση Πίνακα Δομών
Ο πίνακας θα χρησιμοποιείται σε πολλά σημεία του προγράμματος Ορίζεται ως εξωτερική (global) μεταβλητή
struct key keytab[] = { {"account",0}, ... {"programming",0}, {"unix",0}
};
Κάθε ζεύγος αντι-στοιχεί στα στοι-χεία μιας δομής Τα εσωτερικά
άγκιστρα δεν είναι υποχρε-ωτικά
33
Δομή Προγράμματος
Η συνάρτηση main καλεί συνεχώς τη συνάρτηση getword Διαβάζει από την είσοδο μία λέξη τη φορά
Κάθε λέξη αναζητείται μέσα στον πίνακα keytab χρησιμοποιώντας «δυαδική αναζήτηση» (binary search)
Η λίστα των λέξεων-κλειδιών πρέπει να είναι ταξινομημένη σε αύξουσα σειρά
34
Συνάρτηση main
main() {int n;char word[MAXWORD];
while (getword(word, MAXWORD) != 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);
getchar(); //Για να προλάβουμε να δούμε τα αποτελέσματα
}
Κάθε κλήση στην getword βρίσκει μια λέξη και την αντιγράφει στον
πίνακα word
Δυαδική αναζήτηση του string word στον πίνακα keytab
Αυξάνεται ο αντί-στοιχος counter
Εκτύπωση αποτελεσμάτων
35
Επικεφαλίδες
#include <stdio.h>#include <ctype.h> #include <string.h>
#define MAXWORD 100
#define NKEYS (sizeof keytab / sizeof(struct key))
Τελεστής compile-time Επιστρέφει το μέγεθος μιας δομής
δεδομένων
Αριθμός λέξεων-κλειδιών
Μέγεθος ολόκλη-ρου του πίνακα
Μέγεθος ενός στοιχείου του πίνακα
36
int binsearch(char *word, struct key tab[], int n) { int cond, low, high, mid;
low = 0; high = n - 1;while (low <= high) {
mid = (low+high) / 2;if ((cond = strcmp(word,tab[mid].word)) < 0)
high = mid - 1;else if (cond > 0)
low = mid + 1;else
return mid;}return -1;
}
Συνάρτηση binsearch
• Συγκρίνω το string word με το string στη θέση mid του πίνακα
• Αρχικά πρόκειται για το μέσο του πίνακα
• Αν το word είναι μικρότερο, η επόμενη αναζήτηση θα γίνει στο μέσο του μισού πίνακα (προς τα κάτω)
• Αν το word είναι μεγαλύτερο, η επόμενη αναζήτηση θα γίνει στο μέσο του μισού πίνακα (προς τα πάνω)
• Αλλιώς, βρέθηκε
• Αν το «κάτω» ξεπεράσει το «πάνω», τότε δεν βρέθηκε
37
Συνάρτηση getwordint getword(char *word, int lim) {
int c; char *w = word;
while (isspace(c = getchar())) ;if (c != EOF) *w++ = c;if (!isalpha(c)) {
*w = '\0';return c;
}for ( ; --lim > 0; w++)
if (!isalnum(*w = getchar())) {ungetch(*w);break;
}*w = '\0';return word[0];
}
Διαβάζει χαρακτήρες σε έναν buffer και επιστρέφει τον πρώτο χαρακτήρα του buffer
Επιστρέφει έναν χαρακτήρα πίσω στο buffer
Αγνοεί τα αρχικά κενά
Διαβάστηκε κάποιος «σωστός» χαρακτήρας
Αν δε διαβάστηκε γράμμα σταμάτα Κύριος βρόχος ανάγνωσης,
μέχρι να συναντηθεί μη-αλφαριθμητικός χαρακτήρας
38
Εναλλακτικό πρόγραμμα – Χρήση Δεικτών σε Δομές - main
main() {
char word[MAXWORD];
struct key *p;
while (getword(word, MAXWORD) != EOF)
if (isalpha(word[0]))
if ((p=binsearch(word,keytab,NKEYS)) != NULL)
p->count++;
for (p = keytab; p < keytab + NKEYS; p++)
if (p->count > 0)
printf("%4d %s\n", p->count, p->word);
}
39
struct key *binsearch(char *word,struct key *tab,int n) {int cond;struct key *low = &tab[0];struct key *high = &tab[n];struct key *mid;
while (low < high) {mid = low+(high-low)/2;if ((cond = strcmp(word, mid->word)) < 0)
high = mid;else if (cond > 0)
low = mid + 1;else
return mid;}return NULL;
}
Εναλλακτικό πρόγραμμα – Χρήση Δεικτών σε Δομές - binsearch
Η συνάρτηση πλέον επιστρέφει pointers και όχι ακεραίους
Η προσπέλαση στοι-χείων του keytab γίνεται πλέον με δείκτες
• Αρχικά εκτός ορίων πίνακα
• Η αριθμητικές πρά-ξεις δεικτών εξα-σφαλίζουν σωστό αποτέλεσμα
40
Ένωση (union)
Είναι μια θέση μνήμης που μπορεί να χρησιμοποιηθεί από πολλές μεταβλητές διαφορετικού τύπου
Δήλωση παρόμοια με τη δήλωση μιας δομής
union paradeigma { int i; char ch;};
41
Μεταβλητές union
Μια μεταβλητή union μπορεί να δηλωθεί τοποθετώντας το όνομα της μαζί
με τη δήλωση του union, ήΜετά, σαν μια ξεχωριστή δήλωση
union paradeigma x1;
42
Μεταβλητές union και Μνήμη
Ο ακέραιος i και ο χαρακτήρας ch μοιράζονται τον ίδιο χώρο μνήμης.
Ο i καταλαμβάνει 2 bytes ενώ ο ch 1
Byte 0 Byte 1
i
ch
43
Μεταβλητές union και Μνήμη
Όταν δηλώνεται ένα union, ο μεταγλωττιστής αυτόματα κρατάει χώρο στη μνήμη για τον μεγαλύτερο τύπο μεταβλητής που υπάρχει μέσα στο union.
44
Προσπέλαση στοιχείων union
Παρόμοια με τις δομές Αν χρησιμοποιούμε απευθείας μεταβλητή
union, χρησιμοποιούμε τον τελεστή τελεία
Αν χρησιμοποιούμε δείκτη προς union, τότε χρησιμοποιούμε τον τελεστή βέλος
Π.χ., για ανάθεση της τιμής 10 στην ακέραια μεταβλητή i:
x1.i = 10;