ΠΛΗ111 οµηµένος Προγραµµατισµός Ανοιξη 2005 Μάθηµα 1 ο Ανασκόπηση της Γλώσσας Προγραµµατισµού C Τµήµα Ηλεκτρονικών Μηχανικών και Μηχανικών Υπολογιστών Πολυτεχνείο Κρήτης
Ανασκόπηση της C είκτες Πίνακες Κλήση συναρτήσεων Συµβολοσειρές οµές υναµική καταχώρηση µνήµης Συχνά προγραµµατιστικά σφάλµατα οµή Προγράµµατος Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 2
Μνήµη Υπολογιστή Η µνήµη του υπολογιστή µπορεί να θεωρηθεί ως αριθµηµένη ακολουθία από µονάδες αποθήκευσης Κάθε µονάδα µπορεί να αποθηκεύσει 1 byte ιεύθυνση µιας µονάδας είναι η θέση της στην ακολουθία µονάδες αποθήκευσης i i+1 διευθύνσεις µονάδων Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 3
Μια µεταβλητή Μεταβλητές Εχει συµβολικό όνοµα Τύπο δεδοµένων Καταλαµβάνει µια ή περισσότερες µονάδες αποθήκευσης Εχει διεύθυνση τη θέση της πρώτης µονάδας αποθήκευσης Π.χ. int p; µεταβλητή p i i+1 διεύθυνση µεταβλητής Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 4
Ο δείκτης είναι µεταβλητή είκτες Αποθηκεύει τη διεύθυνση µιας µονάδας αποθήκευσης Εχει τύπο που καθορίζει τη χρήση της µνήµης που δείχνει ηλώνεται µε το σύµβολο * Π.χ. int *ip; δείκτης ip διεύθυνση µεταβλητής τύπου int Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 5
Προσπέλαση είκτη Τελεστής αναφοράς & (reference) Προσπέλαση της διεύθυνσης µιας µεταβλητής Τελεστής έµµεσης αναφοράς * (dereference) Προσπέλαση της µεταβλητής που δείχνεi o δείκτης ιαφορετικός από το συµβολισµό δήλωσης του δείκτη Π.χ. int *ip; int x = 1; ip = &x; *ip = 2; δείκτης ip µεταβλητή x 1 2 Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 6
Dangling Reference Απλή δήλωση δείκτη δεν καταχωρεί µνήµη αναφοράς Έµµεση αναφορά χωρίς αρχικοποίηση του δείκτη Προσπάθεια προσπέλασης απροσδιόριστης διεύθυνσης Πρόωρος τερµατισµός εκτέλεσης κώδικα από το σύστηµα Π.χ. int *ip; *ip = 2; δείκτης ip απροσδιόριστη διεύθυνση πρόωρος τερµατισµός Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 7
είκτης NULL Ειδική σταθερά δείκτη Ισοδυναµεί µε το 0 Υποδηλώνει µια ανύπαρκτη µεταβλητή Έµµεση αναφορά µέσω NULL οδηγεί σε τερµατισµό Π.χ. int *ip; δείκτης ip ip = NULL; Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 8
είκτες και Πίνακες Η δήλωση ενός πίνακα καταχωρεί στη µνήµη µια σειρά από µεταβλητές του ίδιου τύπου (στοιχεία του πίνακα) Ο συµβολισµός δείκτη προσφέρει έναν εναλλακτικό (ταχύτερο) τρόπο προσπέλασης των στοιχείων πίνακα Π.χ. int a[5]; a[0] a[1] a[2] a[3] a[4] *a *(a+1) *(a+2) *(a+3) *(a+4) Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 9
Αριθµητική εικτών Ένας δείκτης µε κατάλληλη αρχικοποίηση µπορεί να προσπελάσει τα στοιχεία ενός πίνακα ίδιου τύπου Όταν ο δείκτης pa δείχνει κάποιο στοιχείο ενός πίνακα, ο δείκτης pa+i δείχνει στο στοιχείο i θέσεις δεξιά, και ο δείκτης pa-i δείχνει στο στοιχείο i θέσεις αριστερά Π.χ. int a[5]; int *pa; πίνακας a τύπου int pa = &a[2]; a+2 *(pa-2) *(pa-1) *pa *(pa+1) *(pa+2) Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 10
Κλήση κατ Αξία (by value) Aντιγράφει τις τιµές των ορισµάτων a και b στις τοπικές µεταβλητές x και y Αφήνει ίδιες τις τιµές των µεταβλητών a, b void swap(int x, int y) { int temp; swap : x 1 2 } temp = x; x = y; y = temp; y a 2 1 1 int a = 1, b = 2; b 2 swap(a,b); Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 11
Κλήση κατ αναφορά (by reference) Eπιτρέπει προσπέλαση των ορισµάτων a και b µέσω των τοπικών µεταβλητών - δεικτών -pxκαι py Εναλλάσσει τις τιµές των µεταβλητών a, b void swap(int *px, int *py) { int temp; } temp = *px; *px = *py; *py = temp; int a = 1, b = 2; swap(&a, &b); swap : px py a b 1 2 2 1 Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 12
Συµβολοσειρές (strings) Πίνακες τύπου char µε τελευταίο στοιχείο το \0 Π.χ. char astring[] = Hello world ; astring: H e l l o w o r l d \0 Παράδειγµα συνάρτησης αντιγραφής συµβολοσειρών void strcopy(char *s, char *t) { int i = 0; while ((s[i] = t[i])!= /0 ) i++; } char a[] = Hello world, b[12]; strcopy(b, a); a b H e l l o w o r l d \0 Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 13
Συµβολοσειρές και είκτες Οι δείκτες συντοµεύουν τη διαχείριση συµβολοσειρών Π.χ. συντοµότερη εκδοχή της συνάρτησης αντιγραφής void strcopy(char *s, char *t) { while (*s++ = *t++) ; } char a[] = Hello world, b[12]; strcopy(b, a); a b H e l l o w o r l d \0 Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 14
είκτες σε Πίνακες (ή είκτες σε είκτες) Θεωρούµε δύο δείκτες σε ξεχωριστές συµβολοσειρές Θέλουµε να γράψουµε συνάρτηση που εναλλάσσει τις συµβολοσειρές στις οποίες δείχνουν οι δύο δείκτες Πριν Μετά a Hello world\0 a Hello world\0 b Good bye\0 b Good bye\0 Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 15
Εναλλαγή Συµβολοσειρών Για να προσπελάσουµε τις συµβολοσειρές µέσα από συνάρτηση χρησιµοποιούµε ορίσµατα τύπου char ** void strswap(char **pa, char **pb) { char *temp; } temp = *pa; *pa = *pb; *pb = temp; pa pb a b Hello world\0 Good bye\0 char *a = Hello world ; char *b = Good bye ; strswap(&a, &b); Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 16
Πίνακες εικτών Ένα πρόγραµµα µπορεί να προσπελάσει παραµέτρους της γραµµής εκτέλεσης εντολών Π.χ. C:> echo Hello, world Η προσπέλαση γίνεται µέσω ορισµάτων της main() #include <stdio.h> int main(int argc, char **argv) { int i; } argv for (i = 1; i < argc; i++) printf(( %s%s, argv[i], (i < argc 1)? : ); printf( \n ); exit(0); 0 1 argc-1 echo\0 Hello,\0 world\0 Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 17
οµή Συλλογή µιας ή περισσότερων µεταβλητών (µελών) ενδεχοµένως διαφορετικών τύπων δεδοµένων ηλώνεται µε τη δεσµευµένη λέξη struct struct point { struct point { int x; int x; int y; ή int y; }; } pt1, pt2; struct point pt1, pt2; pt1 x y pt2 x y Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 18
Λειτουργίες µε οµές Υποστηρίζονται Αρχικοποίηση µε λίστα σταθερών Π.χ. struct point pt1 = {1, 2}; Αντιγραφή και απόδοση τιµής σαν σύνολο Π.χ. pt2 = pt1; Προσπέλαση µελών Π.χ. printf( %d %d, pt1.x, pt1.y); Αναφορά στη δοµή σαν σύνολο, ή σε ξεχωριστά µέλη της δοµής Π.χ. struct point *ppt = &pt1; int *z = &(pt1.x); εν υποστηρίζεται γενικά Σύγκριση δοµών σαν σύνολο Π.χ. (pt1 == pt2) Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 19
Η δήλωση µιας δοµής Αυτοαναφορικές οµές εν µπορεί να έχει ως µέλος δοµή του ίδιου τύπου Mπορεί όµως να περιέχει δείκτη σε δοµή του ίδιου τύπου /* άκυρη */ /* έγκυρη */ struct S { struct S { int a; int a; struct S next; struct S *next; } s; } s; Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 20
typedef Εναλλακτικά µπορούµε να δηλώσουµε µια αυτοαναφορική δοµή κάνοντας χρήση της δεσµευµένης λέξης typedef typedef struct S *Sptr; typedef struct S { int a; Sptr next; } Sstruct; Sstruct s; a s Sptr Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 21
Καταχώρηση Μνήµης (1) Τοπική Μνήµη (local memory, stack) Χρησιµοποιείται από τις τοπικές µεταβλητές των συναρτήσεων Καταχωρείται αυτόµατα κατά την κλήση µιας συνάρτησης Αποδεσµεύεται αυτόµατα κατά την έξοδο από µια συνάρτηση Το µέγεθος καθορίζεται από τους τύπους των µεταβλητών Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 22
Χρήση Τοπικής Μνήµης void X() { void Y(int p) { int a = 1; int q; int b = 2; q = p + 2; } Y(a); Y(b); } Y(a) p:1 q:3 Y(b) p:2 q:4 X() a:1 b:2 X() a:1 b:2 X() a:1 b:2 X() a:1 b:2 X() a:1 b:2 Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 23
Σφάλµα Χρήσης Τοπικής Μνήµης // Επιστρέφει δείκτη σε int int* TAB() { int temp; // είκτης σε τοπική µεταβλητή int return(&temp); } void Victim() { int* ptr; ptr = TAB(); *ptr = 42; // Σφάλµα εκτέλεσης! } Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 24
Καταχώρηση Μνήµης (2) υναµική Μνήµη (heap) Η καταχώρηση ελέγχεται από το χρήστη H αποδέσµευση ελέγχεται από το χρήστη Το δεσµευµένο µέγεθος καθορίζεται από το χρήστη Αυξάνει την πιθανότητα σφαλµάτων προγραµµατισµού! Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 25
Καταχώρηση υναµικής Μνήµης Τοπικές µεταβλητές-δείκτες δείχνουν σε τµήµατα της δυναµικής µνήµης που έχουν δεσµευτεί Τοπική Μνήµη υναµική Μνήµη ιαθέσιµη Μεταβλητή 3 Μεταβλητή 2 Μεταβλητή 1 Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 26
Αποδέσµευση υναµικής Μνήµης Τοπικές µεταβλητές-δείκτες δείχνουν σε τµήµατα δυναµικής µνήµης ακόµη και µετά την αποδέσµευση Τοπική Μνήµη υναµική Μνήµη ιαθέσιµη Μεταβλητή 3 ιαθέσιµη Μεταβλητή 1 Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 27
Λειτουργίες υναµικής Μνήµης void* malloc(unsigned long size); έχεται ως όρισµα το µέγεθος του τµήµατος που θα καταχωρηθεί στη δυναµική µνήµη Επιστρέφει δείκτη γενικού τυπου (void*) στο τµήµα δυναµικής µνήµης που καταχωρήθηκε void free(void* heapblockpointer); έχεται ως όρισµα δείκτη σε τµήµα µνήµης που θα αποδεσµευτεί κατά την κλήση Το όρισµα πρέπει να είναι ακριβώς ο ίδιος δείκτης που επέστρεψε προηγούµενη κλήση της malloc() εν επιστρέφει τίποτα Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 28
Χρήση υναµικής Μνήµης Καταχώρηση δυναµικής µνήµης για µεταβλητή τύπου int γίνεται µε απαίτηση µεγέθους sizeof(int) Τοπική υναµική void Heap1() { int* intptr; intptr = (int *) malloc(sizeof(int)); *intptr = 42; intptr intptr 42 } free(intptr); intptr Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 29
ιαρροή Μνήµης (memory leak) Όταν ένα πρόγραµµα καταχωρεί δυναµική µνήµη χωρίς να την αποδεσµεύει µετά το πέρας της χρήσης της Μπορεί το πρόγραµµα να εξαντλήσει όλη τη δυναµική µνήµη και να τερµατιστεί πρόωρα char* StringCopy(const char* string) { char* newstring; int len; } len = strlen(string) + 1; /* +1 για το '\0' */ newstring = (char *) malloc(sizeof(char)*len); assert(newstring!= NULL); /* έλεγχος σφάλµατος */ strcpy(newstring, string); return(newstring); Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 30
Προγραµµατιστικά Σφάλµατα (1) Βρείτε το σφάλµα στο παρακάτω πρόγραµµα #include <stdio.h> int main( void ) { int i; scanf( "%d", &i ); if( i = 0 ) puts( "false" ); else puts( "true" ); } exit(0); Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 31
Προγραµµατιστικά Σφάλµατα (2) Βρείτε το σφάλµα στο παρακάτω πρόγραµµα #include <stdio.h> int main( void ) { int i; } scanf( "%d", i ); printf( "input = %d\n", i ); exit(0); Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 32
Προγραµµατιστικά Σφάλµατα (3) Βρείτε το σφάλµα στο παρακάτω πρόγραµµα #include <stdio.h> int main( void ){ int *pc; } scanf( "%d", pc ); printf( "%d\n", pc ); exit(0); Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 33
Προγραµµατιστικά Σφάλµατα (4) Βρείτε το σφάλµα στο παρακάτω πρόγραµµα #include <stdlib.h> int main( void ){ double *p; p = malloc (sizeof (double *)); } exit(0); Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 34
Προγραµµατιστικά Σφάλµατα (5) Βρείτε το σφάλµα στο παρακάτω πρόγραµµα #include <stdio.h> int main( void ) { char s[] = "hi"; if (s == "hi") puts ("Strings are equal"); else puts ("Strings are not equal"); } exit(0); Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 35
οµή Προγράµµατος Όταν σχεδιάζουµε µεγάλα προγράµµατα συνίσταται να τα διαιρούµε σε τµήµατα (modules) Οµαδοποιούν συσχετιζόµενες συναρτήσεις Αναπτύσσονται παράλληλα από διαφορετικές οµάδες Τροποποιούνται ανεξάρτητα το ένα από το άλλο Επαναχρησιµοποιούνται σε διαφορετικά προγράµµατα Όταν ένα τµήµα αλλάζει, µεταγλωττίζεται ξανά µόνο αυτό Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 36
Εσωτερικές Μεταβλητές Ορίζονται στο εσωτερικό µιας συνάρτησης (τοπικές) Χρησιµοποιούνται µόνο από τη συνάρτηση αυτή Εξωτερικές Ορίζονται εξωτερικά από κάθε συνάρτηση Μπορούν εν δυνάµει να χρησιµοποιηθούν από όλο το πρόγραµµα Παραµένουν ενεργές καθόλη τη διάρκεια εκτέλεσης προγράµµατος Η εµβέλειά τους ξεκινάει στο σηµείο της δήλωσης και τελειώνει στο τέλος του αρχείου της δήλωσης Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 37
Εξωτερικές Μεταβλητές Ορισµός (definition, defining declaration) Γίνεται µόνο µία φορά µέσα σε ένα πρόγραµµα Καθορίζει τον τύπο της µεταβλητής Καταχωρεί µνήµη για την αποθήκευση των δεδοµένων Π.χ. int errorcount = 0; ήλωση (declaration, referencing declaration) Μπορεί να γίνει πολλαπλώς µέσα σε ένα πρόγραµµα Καθορίζει τον τύπο της µεταβλητής Π.χ. extern int errorcount; Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 38
Περιέχουν ηλώσεις µεταβλητών Αρχεία Επικεφαλίδας Πρωτότυπα συναρτήσεων Εντολές του προεπεξεργαστή Εξασφαλίζουν επικοινωνία µεταξύ διαφορετικών τµηµάτων του προγράµµατος εν περιέχουν εκτελέσιµο κώδικα, όπως ορισµούς και αρχικοποιήσεις µεταβλητών ή συναρτήσεις Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 39
Πρόγραµµα Πολλαπλών Αρχείων header.h #define MY_STRING "Hello World" extern char *anotherstring; void writemystring(char *thisstring); main.c #include <stdio.h> #include "header.h" char *anotherstring = "Hello Everyone"; main() { printf("running...\n"); writemystring(my_string); printf("finished.\n"); } #include <stdio.h> #include "header.h" write.c void writemystring(char *thisstring) { printf("%s\n", thisstring); printf("global Variable = %s\n", anotherstring); } Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 40