ΠΛΥ410 Προγραμματιςμόσ Συςτημάτων Διδάςκων: Β. Δημακόπουλοσ dimako@cs.uoi.gr
Εργαςτιρια Ξεκινοφν τθν Τρίτη, 11/3 Από αφριο το πρωί εγγραφζσ: Καταςτάςεισ ςτον 2 ο όροφο, Γραφείο Β32 () Ομάδεσ των 2 Βοθκοί εργαςτθρίου: Σπφροσ Αγάκοσ (Υποψιφιοσ Διδάκτορασ) Βαγγζλθσ Λάππασ (Υποψιφιοσ Διδάκτορασ) Αλζξανδροσ Ραπαδογιαννάκθσ (Μεταπτυχιακόσ Φοιτθτισ) Guest star / φιλικι ςυμμετοχι: Χριςτοσ Γιαννάκοσ (Μεταπτυχιακόσ Φοιτθτισ) 2
Ώρεσ Βοθκοί Γραφείο Β32 08:00 09:00 10:00 11:00 Δε Τρ Τε Πε Πα Σα Κυ Γρ Ώρεσ γραφείου βοθκϊν: 12:00 13:00 Δ Δ Δευτζρα: 14:00 16:00 Τετάρτθ : 14:00 16:00 Ραραςκευι: 16:00 18:00 14:00 15:00 16:00 17:00 Β Β Εργ Β Β Β Β 18:00 Ιςτοςελίδα μακιματοσ: http://www.cs.uoi.gr/~dimako/courses/ 3
Η γλώςςα C Συναρτήςεισ
Συναρτιςεισ Ρρόκειται απλά για μια ακολουκία εντολϊν τθν οποία χρθςιμοποιοφμε ςε αρκετά ςθμεία του προγράμματόσ μασ και τθν οποία τθν ξεχωρίηουμε ωσ «υποπρόγραμμα», ϊςτε να μπορεί να κλθκεί και να εκτελεςτεί όςεσ φορζσ κζλουμε. «Μζκοδοι» ςτθν Java. Στθ C δεν αποτελοφν μζροσ καμίασ κλάςθσ (δεν υπάρχουν κλάςεισ), καλοφνται από παντοφ. 5
Τα 3 βαςικά ςθμεία των ςυναρτιςεων: (α) πρωτότυπο Ρρωτότυπο (prototype) function declaration δήλωςη (declaration) που περιγράφει τι χρειάηεται θ ςυνάρτθςθ για να λειτουργιςει και τι είδουσ αποτζλεςμα κα επιςτρζψει: <τύποσ_επιςτροφόσ> όνομα_ςυναρτηςησ (<τύποσ_παραμϋτρου> παρϊμετροσ,...) ; Ρ.χ. int power(int base, int exponent); Είναι απαραίτθτο το πρωτότυπο; Απάντθςθ: όχι πάντα, αλλά αν δεν το γράψετε μπορεί να δθμιουργθκοφν προβλιματα. Θεωρείςτε το ιςοδφναμο με τθ δήλωςη μίασ μεταβλητήσ (θ οποία πρζπει να οριςτεί / δθλωκεί πριν τθν χρθςιμοποιιςετε) 6
Τα 3 βαςικά ςθμεία των ςυναρτιςεων: (β) οριςμόσ Οριςμόσ / υλοποίθςθ τθσ ςυνάρτθςθσ function definition <πρωτότυπο> /* Προςοχό: χωρύσ το ; */ {... /* οι εντολϋσ τησ ςυνϊρτηςησ */ return (<τιμό>); Η return: τερματίηει τθ ςυνάρτθςθ και επιςτρζφει το αποτζλεςμα. Τι ςθμαίνει επιςτρζφει το αποτζλεςμα? Αν ζχω ςτθ main() : εκτζλεςε τθ ςυνάρτθςθ power για τα 2, 4 τότε ό,τι τιμι γίνεται return αποκθκεφεται ςε μια προςωρινι κζςθ μνιμθσ tmp. res = power(2, 4) res = tmp όπου ςτο tmp ζχει μπει το 2 4, δθλ. το 16 Ειδικόσ τφποσ ςυνάρτθςθσ: void Αν θ ςυνάρτθςθ είναι τφπου void τότε ΔΕΝ επιςτρζφει τίποτε Ζχουμε ςκζτο: return; 7
Τα 3 βαςικά ςθμεία των ςυναρτιςεων: (γ) κλήςη Κλιςθ μίασ ςυνάρτθςθσ function call Μζςα ςτο πρόγραμμα εκτζλεςε τθ ςυνάρτθςθ power για τα 2, 4 και υπολόγιςε το αποτζλεςμα Τρόποσ πλιςθσ: <όνομα_ςυνϊρτηςησ>(τιμϋσ για πραγματικϋσ παραμϋτρουσ) 8
Ραράδειγμα #include <stdio.h> int main() { int x, y, k, n, res; int power(int base, int n); /* πρωτότυπο */ x = 2; y=3; k=4; n=2; res = power(x, k); /* κλήςη */ printf( %d \n, res); res = power(y, n); /* κλήςη */ printf( %d \n, res); Ραράμετροι (parameters) ι τυπικζσ παράμετροι (formal parameters) Ορίςματα (arguments) ι πραγματικζσ παράμετροι return 0; /* Η main() πρϋπει να επιςτρϋφει 0 αν όλα ΟΚ */ /* Οριςμόσ (υπολογύζει το base υψωμϋνο ςτη δύναμη n, base n ) */ int power(int base, int n) { int i, p; for (i = p = 1; i <= n; i++) p = p*base; return p; /* τιμό επιςτροφόσ */ 9
Ραράδειγμα αλλοφ το πρωτότυπο #include <stdio.h> int power(int base, int n); /* πρωτότυπο */ int main() { int x, y, k, n, res; x = 2; y=3; k=4; n=2; res = power(x, k); /* κλόςη */ printf( %d \n, res); res = power(y, n); /* κλόςη */ printf( %d \n, res); ΔΙΑΦΟΑ ΜΕ ΡΙΝ: Πχι μόνο θ main(), αλλά ΟΛΕΣ οι επόμενεσ ςυναρτιςεισ κα «γνωρίηουν» τθν power(). Ρριν, ΜΟΝΟ ςτθν main() είχε γίνει γνωςτι! return 0; /* Η main() πρϋπει να επιςτρϋφει 0 αν όλα ΟΚ */ /* Οριςμόσ (υπολογύζει το base^n) */ int power(int base, int n) { int i, p; for (i = p = 1; i <= n; i++) p = p*base; return p; /* τιμό επιςτροφόσ */ 10
Ραράδειγμα χωρίσ πρωτότυπο. Τι κα γίνει; #include <stdio.h> int main() { int x, y, k, n, res; x = 2; y=3; k=4; n=2; res = power(x, k); /* κλόςη */ printf( %d \n, res); res = power(y, n); /* κλόςη */ printf( %d \n, res); ΑΡΟΤΕΛΕΣΜΑ: Compiler warnings: δεν «γνωρίηει τθν power() ςτα ςθμεία που γίνονται οι δφο κλιςεισ. Ρολλζσ φορζσ υπάρχουν και καταςτροφικά αποτελζςματα. return 0; /* Η main() πρϋπει να επιςτρϋφει 0 αν όλα ΟΚ */ /* Οριςμόσ (υπολογύζει το base^n) */ int power(int base, int n) { int i, p; for (i = p = 1; i <= n; i++) p = p*base; return p; /* τιμό επιςτροφόσ */ 11
Ραράδειγμα χωρίσ πρωτότυπο. Τι κα γίνει; #include <stdio.h> /* Οριςμόσ (υπολογύζει το base^n) */ int power(int base, int n) { int i, p; for (i = p = 1; i <= n; i++) p = p*base; return p; /* τιμό επιςτροφόσ */ int main() { int x, y, k, n, res; ΑΡΟΤΕΛΕΣΜΑ: Μιασ και θ ςυνάρτθςθ ορίςτθκε ΡΙΝ τα ςθμεία των δφο κλιςεων, ΘΕΩΕΙΤΑΙ ΓΝΩΣΤΗ. Επομζνωσ δεν δθμιουργείται πρόβλθμα και άρα δεν είναι απαραίτθτο το πρωτότυπο. ΜΗΝ ΤΟ ΚΑΝΕΤΕ!! ΡΑΝΤΑ ΝΑ ΓΑΦΕΤΑΙ ΤΑ ΡΩΤΟΤΥΡΑ!! x = 2; y=3; k=4; n=2; res = power(x, k); /* κλόςη */ printf( %d \n, res); res = power(y, n); /* κλόςη */ printf( %d \n, res); return 0; /* Η main() πρϋπει να επιςτρϋφει 0 αν όλα ΟΚ */ 12
int power(int base, int n) { int i, p; for (i = p = 1; i <= n; i++) p = p*base; return p; Κανζνα πρόβλθμα; Τι γίνεται αν n < 0? Ρωσ κα το άλλαηα για να ελζγχει αν το n είναι κετικόσ; if (n < 0) { return (-1); 13
Ζτοιμεσ μακθματικζσ ςυναρτιςεισ ςτθ C Ρρζπει: #include <stdio.h> #include <math.h> void main() { printf( cos(0) = %lf\n, cos(0.0)); Επίςθσ, κατά τθ μεταγλϊττιςθ, πρζπει να ςυμπεριλθφκεί και θ βιβλιοκικθ των μακθματικϊν ςυναρτιςεων με το lm: % gcc prog.c -lm % ls a.out prog.c libm prog.c gcc a.out 14
Συνικεισ μακθματικζσ ςυναρτιςεισ double acos(double); double asin(double); double atan(double); double cos(double); double cosh(double); double sin(double); double sinh(double); double tan(double); double tanh(double); double sqrt(double); double exp(double); double pow(double, double); double log(double); double log10(double); double fabs(double); 15
Ρζραςμα Ραραμζτρων Οι μεταβλθτζσ βαςικοφ τφπου (int, char, float, ) περνιοφνται ωσ παράμετροι ςε μια ςυνάρτθςθ με τιμή (by value). δθλαδι αντιγράφονται οι τιμζσ τουσ ςε τοπικζσ μεταβλθτζσ τθσ ςυνάρτθςθσ. όποιεσ αλλαγζσ γίνουν ςε αυτζσ τισ τιμζσ των μεταβλθτϊν ςτο εςωτερικό τθσ ςυνάρτθςθσ δεν είναι εμφανείσ ςτο κομμάτι του προγράμματοσ ςτο οποίο ζγινε θ κλιςθ τθσ ςυνάρτθςθσ. Αν κζλουμε να ξεπεράςουμε τον παραπάνω περιοριςμό, δθλ. ότι αλλαγζσ γίνουν ςτισ τιμζσ των μεταβλθτϊν ςτο εςωτερικό τθσ ςυνάρτθςθσ να είναι εμφανείσ ςτο κομμάτι του προγράμματοσ ςτο οποίο ζγινε θ κλιςθ τθσ ςυνάρτθςθσ, μποροφμε να περάςουμε τισ διευκφνςεισ των κζςεων μνιμθσ που ζχουν δεςμευκεί για τισ μεταβλθτζσ, να κάνουμε όπωσ λζμε πζραςμα με αναφορά (by reference, με χριςθ παραμζτρων τφπου pointer). Οι παράμετροι τφπου πίνακα πάντα περνιοφνται με αναφορά. όποιεσ αλλαγζσ γίνουν ςτα ςτοιχεία του πίνακα είναι εμφανείσ ςτο κομμάτι του προγράμματοσ ςτο οποίο ζγινε θ κλιςθ τθσ ςυνάρτθςθσ. 16
swap #include <stdio.h> void swap (int x, int y); main() { int a,b; a = 6; b = 7; swap(a, b); printf( %d %d\n, a, b); return 0; void swap (int x, int y) { int temp; temp = x; x = y; y = temp; return; #include <stdio.h> void swap (int *x1, int *x2); main() { int a,b; a = 6; b = 7; swap(&a, &b); printf( %d %d\n, a, b); return 0; void swap (int *x1, int *x2) { int temp; temp = *x1; *x1 = *x2; *x2 = temp; return; 17
Ραράδειγμα πζραςμα by reference με πίνακα #include <stdio.h> void f(int a[]); main() { int i; int x[] = {1, 2; f(x); for (i = 0; i < 2; i++) printf( %d\n, x[i]); X[0] X[1] 1 2 4bytes 4bytes void f(int k[]) { int i; for (i = 0; i < 2; i++) k[i] = k[i]*2; return; 18
Στοίβα (stack) Για κάκε κλιςθ ςυνάρτθςθσ ζχω ζνα κομμάτι μνιμθσ αφιερωμζνο ςε αυτι Δεςμεφεται αυτόματα κατά τθν είςοδο ςτθ ςυνάρτθςθ και αποδεςμεφεται επίςθσ αυτόματα κατά τθν ζξοδο από αυτι Η χϊροσ μνιμθσ που χρθςιμοποιείται για το ςκοπό αυτό καλείται stack (ςτοίβα) Το ςυγκεκριμζνο κομμάτι μνιμθσ για μια ςυνάρτθςθ καλείται stack frame Στθ μνιμθ αυτι (stack frame) τοποκετοφνται οι παράμετροι και οι τοπικζσ μεταβλθτζσ μιασ ςυνάρτθςθσ 19
Η γλώςςα C Εμβέλεια και διάρκεια ζωήσ μεταβλητών (scope & lifetime)
Εμβζλεια μεταβλθτϊν (scope / visibility) Τι είναι: Η εμβζλεια του ονόματοσ μιασ μεταβλθτισ είναι το τμήμα του προγράμματοσ ςτο οποίο η μεταβλητή μπορεί να χρηςιμοποιηθεί Global (κακολικι) Local (τοπικι, ςε ςυνάρτθςθ) Block (ςε δομθμζνο μπλοκ εντολϊν {.. ) Εμβζλεια τοπικϊν μεταβλθτϊν δθλϊνονται ςτθν αρχι κάκε ςυνάρτθςθσ και μποροφν να χρθςιμοποιθκοφν μόνο μζςα ςτθ ςυνάρτθςθ Εμβζλεια block δθλϊνεται ςτθν αρχι ενόσ δομθμζνου block { και είναι ορατό μόνο μέσα στο block αυτό! Εμβζλεια κακολικϊν μεταβλθτϊν από εκεί που δθλϊκθκαν μζχρι τζλοσ αρχείου 21
Εμβζλεια int i, j; void f(int i) { j = i++; void g() { int k; if (j > 5) { int j; j = f(); k = 2*j; i++; Η εμβζλεια προκφπτει ΜΟΝΟ από το κείμενο του κϊδικα απλά παρατθρϊντασ που είναι τοποκετθμζνεσ οι δθλϊςεισ ςε ςχζςθ με τισ ςυναρτιςεισ και τα blocks ΚΑΙ ΠΧΙ από το πϊσ εκτελείται ο κϊδικασ. main() { g(); 22
Τι κα τυπωκεί; #include <stdio.h> char color = Β ; void paintitgreen(){ char color = G ; printf("color@pib: %c\n", color); void paintitred(){ char color = R ; printf("\n\t-------start pir----\n\t"); printf("color@pir: %c\n\t", color); paintitgreen(); printf("\tcolor@pir: %c\n\t", color); printf("-------end pir----\n\n"); main(){ printf("\t\tcolor@main: %c\n", color); paintitgreen(); printf("\t\tcolor@main: %c\n", color); paintitred(); printf("\t\tcolor@main: %c\n", color); 23
Διάρκεια (lifetime) Το χρονικό διάςτημα για το οποίο δεςμεφεται μνήμη για τισ μεταβλητζσ. Τοπικζσ μεταβλθτζσ: ωσ τθν ολοκλιρωςθ τθσ ςυνάρτθςθσ ςτθν οποία είναι οριςμζνεσ Κακολικζσ: ωσ τθν ολοκλιρωςθ τθσ εκτζλεςθσ του προγράμματοσ Τοπικζσ μεταβλθτζσ: auto (το default, υπάρχουν όςο διαρκεί το block / ςυνάρτθςθ, μιασ και αποκθκεφονται ςυνικωσ ςτθ ςτοίβα) static (διατθρείται ο χϊροσ ακόμα και αν τελειϊςει μία ςυνάρτθςθ) 24
Διάρκεια μνιμθ int i, j; void f(int i) { j = i++; Η διάρκεια προκφπτει από τθν εκτζλεςθ του κϊδικα. void g() { int k; if (j > 5) { int j; j = f(); k = 2*j; i++; main() { g(); 25
Μεταβλθτζσ με διάρκεια static #include <stdio.h> void f(void){ static int y = 0; y++; printf("%d\n",y); 1. Η αρχικοποίθςθ γίνεται κατά τθν εκκίνθςθ του προγράμματοσ δεν γίνεται ςτθν κάκε κλιςθ τθσ ςυνάρτθςθσ. 2. Η μεταβλθτι ςυνεχίηει να υπάρχει ςτθ μνιμθ ακόμα και μετά τθ λιξθ τθσ ςυνάρτθςθσ main(){ int i; for (i=0;i<5;i++) f(); 26
Αρχικοποίθςθ μεταβλθτϊν Με τθ διλωςθ: Οι κακολικζσ (global) και οι τοπικζσ static Αρχικοποιοφνται ΑΥΤΟΜΑΤΑ ςτο μηδζν (0) Οι τοπικζσ (εκτόσ των static) Τυχαία αρχική τιμή (ςυνήθωσ ςκουπίδια) Αρχικοποίθςθ πινάκων: int a[] = {1, 2, ; Από το πλικοσ των ςτοιχείων προκφπτει το μζγεκοσ του πίνακα int a[5] = {1, 2, ; Αν παραπάνω από 5 ςτοιχεία ςτισ αγκφλεσ Error! Αν λιγότερα από 5 ςκουπίδια ςτισ υπόλοιπεσ κζςεισ του a. Αρχικοποίθςθ πινάκων χαρακτιρων: char txt[] = { A, l, a, l, a, \0 ; ι πιο εφκολα: char txt[] = Alala ; 27
Η γλώςςα C Εμβέλεια extern & πολλαπλά αρχεία κώδικα
Ρολλαπλά αρχεία κϊδικα - scope.c #include <stdio.h> #define SCALE 2 int number; int f(int); main() { int y; number = 5; y= f(4*scale); printf( %d, %d\n, number, y); int f(int x) { int y; y = x*scale + number; return (y); 29
Σε δφο αρχεία scope.c #include <stdio.h> #define SCALE 2 int number, f(int param); main() { int y; number = 5; y = f(4*scale); printf( %d, %d\n,number,y); func.c #define SCALE 2 extern int number; int f(int x) { int y; y = x*scale + number; return (y); 30
Με αρχείο επικεφαλίδασ scope.c #include <stdio.h> #include myscope.h int number; main() { int y; number = 5; y = f(4*scale); printf( %d, %d\n,number,y); func.c #include myscope.h int f(int x) { int y; y = x*scale + number; return (y); myscope.h #define SCALE 2 int f(int param); extern int number; 31
Ρολλά αρχεία Χριςθ ςυναρτιςεων από το ζνα ςτο άλλο Διλωςθ prototype Εναλλακτικά, δθμιουργία include file με prototypes Γενικόσ ρόλοσ που παίηουν τα include files? Ρωσ τα κάνω compile? Είτε όλα μαηί: gcc *.c Είτε με χριςθ Makefile γιατί πάντα ελζγχει τι ζχει αλλάξει 32
Με Makefile scope.c #include <stdio.h> #include myscope.h int number; main() { int y; number = 5; y = f(4*scale); printf( %d, %d\n,number,y); myscope.h func.c #include myscope.h int f(int x) { int y; y = x*scale + number; return (y); Makefile scope: scope.o func.o myscope.h gcc o scope scope.o func.o #define SCALE 2 int f(int param); extern int number; func.o: func.c myscope.h gcc c func.c scope.o: scope.c myscope.h gcc c scope.c 33
scope.c Makefile scope: scope.o func.o myscope.h gcc o scope scope.o func.o func.o: func.c myscope.h gcc c func.c scope.o: scope.c myscope.h gcc c scope.c Κανόνασ ςτόχοσ (target) αρχεία απ τα οποία εξαρτάται (προαπαιτοφμενα) εντολι / ενζργεια για να γίνει (θ γραμμι αρχίηει με TAB!!!) Για κάκε αρχείο : gcc c x.c.c.c.o Preprocessor Compiler αμτικαθιστά #include και #define Αρχεία.ο.o άλλα αρχεία.ο gcc o scope.exe scope.ο f.o Linker a.out 34