Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Αγρονόµων Τοπογράφων Μηχανικών Προγραµµατιστικές Τεχνικές Βασίλειος Βεσκούκης ρ. Ηλεκτρολόγος Μηχανικός & Μηχανικός Υπολογιστών ΕΜΠ v.vescoukis@cs.ntua.gr Ρωµύλος Κορακίτης Αστροφυσικός Αναπλ. Καθηγητής ΕΜΠ romylos@survey.ntua.gr Χρήση Συναρτήσεων στην γλώσσα C++
Συναρτήσεις Οι δοµικές µονάδες κάθε προγράµµατος λέγονται «συναρτήσεις» (functions) Μια συνάρτηση περιέχει κάποιες εντολές που επιτελούν µια εργασία όταν εκτελεστούν Μια συνάρτηση µπορεί να δέχεται παραµέτρους από το περιβάλλον κλήσης της, δηλαδή τη συνάρτηση που την κάλεσε: findmax(a,b,c) readabc() Μια συνάρτηση µπορεί να επιστρέφει ένα αποτέλεσµα στο περιβάλλον κλήσης της ή να µην επιστρέφει κανένα αποτέλεσµα: x=max(3,4) printmax(3,4) Γενικοί κανόνες Κάθε πρόγραµµα περιέχει υποχρεωτικά µία συνάρτηση, την main() Κάθε συνάρτηση µπορεί να καλεί άλλες συναρτήσεις ή και τον εαυτό της Το περιβάλλον κλήσης της main() είναι το λειτουργικό σύστηµα ρ. Βασίλειος Βεσκούκης
Συναρτήσεις στην C++ main() d ΤΙΜΗ ΠΟΥ ΕΠΙΣΤΡΕΦΕΙ Η ΣΥΝΑΡΤΗΣΗ int main() { int a, b, c, d; readabc(); //πάνω σχήµα d=findmax(); //κάτω σχήµα d=findmax(a,b,c); printmax(); } readabc() d=findmax() printmax() main() d a,b,c ΠΑΡΑΜΕΤΡΟΙ ΠΟΥ ΕΧΕΤΑΙ Η ΣΥΝΑΡΤΗΣΗ readabc() d=findmax(a,b,c) printmax(d) d void readabc() {... } int findmax() {... return x; } void printmax() {... } int findmax(int k, int l, int m) {... return x; } ρ. Βασίλειος Βεσκούκης
Συναρτήσεις στην C++ Η τυπική µορφή ορισµού µιας συνάρτησης είναι: // Σχόλια για τον σκοπό της συνάρτησης και τις τιµές των παραµέτρων (αν υπάρχουν) // Τύπος ΌνοµαΣυνάρτησης (τύποι και ονόµατα παραµέτρων) { (Ορισµός τοπικών µεταβλητών) (Σώµα εντολών συνάρτησης) (Εντολή επιστροφής αποτελέσµατος) } [Τα στοιχεία που είναι υπογραµµισµένα µπορεί να υπάρχουν ή όχι, ανάλογα µε την περίπτωση] Παράδειγµα: float length(float x, float y) Ο τύπος της συνάρτησης είναι ο τύπος του αποτελέσµατος που επιστρέφει στο περιβάλλον κλήσης της. Αν δεν επιστρέφει αποτέλεσµα, τότε ο τύπος είναι void (κενός) Αντίστοιχα, αν δεν υπάρχουν παράµετροι, η παρένθεση µετά το όνοµα παραµένει κενή ή, προαιρετικά, περιέχει την λέξη void. Η πλήρης εντολή ορισµού της συνάρτησης λέγεται υπογραφή (signature) της συνάρτησης και επιτρέπει στο σύστηµα να διαλέγει την σωστή συνάρτηση που θα χρησιµοποιηθεί στις περιπτώσεις που υπάρχουν περισσότερες συναρτήσεις µε το ίδιο όνοµα (υπερφόρτωση - overloading).
Αντιστοίχηση ορισµάτων και παραµέτρων µιας συνάρτησης Μια συνάρτηση µπορεί να χρησιµοποιεί παραµέτρους για να λαµβάνει τα δεδοµένα που χρειάζεται από το περιβάλλον κλήσης της. Αυτές οι (τυπικές) παράµετροι ορίζονται στην υπογραφή της συνάρτησης και τα ονόµατά τους σηµατοδοτούν αντίστοιχες τοπικές µεταβλητές της συνάρτησης. Την στιγµή που καλείται η συνάρτηση για να εκτελεστεί, οι παράµετροι αποκτούν τιµές που δίνονται από το περιβάλλον κλήσης µε τη µορφή ορισµάτων (arguments) στην εντολή κλήσης της συνάρτησης. Ένα όρισµα µπορεί να είναι οποιαδήποτε σωστή έκφραση (αριθµητική ή λογική, απλή ή σύνθετη) αρκεί να είναι τέτοιου τύπου ώστε να µπορεί να δοθεί ως τιµή της αντίστοιχης παραµέτρου χωρίς σφάλµα (συνήθως είναι του ιδίου τύπου). Παράδειγµα: int main() float length(float x, float y) { {.. S=length(x2-x1,y2-y1) return len;. } Το αποτέλεσµα της συνάρτησης (µεταβλητή len) καταχωρείται στην µεταβλητή S του main.
Παράδειγµα 1 Πρόβληµα: Να σχεδιαστεί και να γραφεί µια συνάρτηση που θα µετατρέπει τιµές γωνίας από βαθµούς σε ακτίνια εδοµένα εισόδου: η τιµή σε grad εδοµένα εξόδου: η τιµή σε rad Μετασχηµατισµοί: rad = grad * π / 200 Τύπος συνάρτησης: float Όνοµα συνάρτησης: grad2rad Παράµετροι: float grad Αποτέλεσµα: (float) rad Τοπική µεταβλητή: float pi (π)
Παράδειγµα 1 (συνέχεια) Συνάρτηση main Συνάρτηση grad2rad Συνάρτηση main Όρισµα Παράµετρος Τιµή συνάρτησης Μεταβλητή gon ==========> grad rad ==========> res Παραδείγµατα: 50 0.7853982 100 1.5707963 200 3.1415927 79.5874 1.2501560
Άσκηση Πρόβληµα: Να σχεδιαστεί και να γραφεί µια συνάρτηση που θα πραγµατοποιεί στρογγύλευση ενός πραγµατικού (θετικού) αριθµού x σε n δεκαδικά ψηφία εδοµένα εισόδου: οι τιµές των x και n εδοµένα εξόδου: η στρογγυλοποιηµένη τιµή xd Μετασχηµατισµοί: xd = (ακέραιο µέρος(x * 10 n + 0.5)) / (10 n ) Τύπος συνάρτησης:... Όνοµα συνάρτησης:... Παράµετροι:... Αποτέλεσµα:... Τοπικές µεταβλητές: Η συνάρτηση «ακέραιο µέρος» βρίσκεται στην βιβλιοθήκη cmath µε το όνοµα floor
Μεταβίβαση τιµών παραµέτρων - 1 Η µεταβίβαση της τιµής ενός ορίσµατος στην παράµετρο µιας συνάρτησης µπορεί να γίνει µε δύο τρόπους: 1. Μεταβίβαση τιµής (by value): η παράµετρος της συνάρτησης έχει δικό της χώρο στην µνήµη (τοπική µεταβλητή) και εκεί αντιγράφεται η τιµή του αντίστοιχου ορίσµατος. Παράδειγµα: void funcone(int a, int b, char v) Αυτός είναι ο τρόπος που χρησιµοποιεί αυτοµάτως η C++ για την µεταβίβαση της τιµής των παραµέτρων. Οποιαδήποτε αλλαγή στην τιµή των µεταβλητών αυτών δεν περνά στο περιβάλλον κλήσης της συνάρτησης (βλέπε και εµβέλεια µεταβλητών) 2. Αναφορά τιµής (by reference): ως παράµετρος της συνάρτησης τοποθετείται η διεύθυνση µνήµης που βρίσκεται το αντίστοιχο όρισµα. Αν η συνάρτηση αλλάξει την τιµή της µεταβλητής αυτής, η αλλαγή θα είναι ορατή και στο περιβάλλον κλήσης της συνάρτησης (πρακτικά, η µεταβλητή αυτή δεν είναι πια τοπική αλλά κοινή και στα δύο περιβάλλοντα). Ο τρόπος αυτός χρησιµοποιείται αυτοµάτως µόνο στην περίπτωση που η παράµετρος είναι πίνακας. Για άλλους τύπους παραµέτρων, η αναφορά τιµής µπορεί να επιτευχθεί µε την προσθήκη του χαρακτήρα & στον τύπο της παραµέτρου. Παράδειγµα: void functwo(int one, int& two, char three, double& four)
Μεταβίβαση τιµών παραµέτρων - 2 Η µεταβίβαση µε αναφορά τιµής είναι χρήσιµη στις εξής περιπτώσεις: 1. Όταν χρειάζεται να αλλάξει κατά την εκτέλεση της συνάρτησης η τιµή της µεταβλητής (δηλαδή του ορίσµατος) και στο περιβάλλον κλήσης 2. Όταν χρειάζεται να «επιστρέψουν» στο περιβάλλον κλήσης οι τιµές για περισσότερες από µία µεταβλητές. Αυτό επιτρέπει να ξεπεραστεί ο περιορισµός της γλώσσας C++ να δέχεται µόνο ένα αποτέλεσµα (τιµή) σε κάθε συνάρτηση 3. Όταν είναι σηµαντική η εξοικονόµηση χώρου µνήµης και χρόνου που χρειάζεται για την αντιγραφή µεγάλων ποσοτήτων δεδοµένων (π.χ. περίπτωση πινάκων)
Παράδειγµα 2 - Χρήση πινάκων ως παραµέτρων µιας συνάρτησης Πρόβληµα: Να σχεδιαστεί και να γραφεί µια συνάρτηση που θα υπολογίζει τη µέγιστη τιµή των στοιχείων ενός µονοδιάστατου πίνακα εδοµένα εισόδου: το πλήθος n των στοιχείων του πίνακα a και οι τιµές τους εδοµένα εξόδου: η µέγιστη τιµή max Τύπος συνάρτησης: float Όνοµα συνάρτησης: arrmax Παράµετροι: float a[ ], int n Αποτέλεσµα: (float) max Τοπική µεταβλητή: int k
Εµβέλεια µεταβλητών Ο όρος εµβέλεια µιας µεταβλητής (scope of name) αναφέρεται στο τµήµα του προγράµµατος στο οποίο έχει εφαρµογή η δήλωση µιας µεταβλητής, δηλαδή αναγνωρίζεται η µεταβλητή. Στην C++, η βασική µονάδα (τµήµα) προγράµµατος είναι το block, µια οµάδα εντολών που περικλείεται σε άγκιστρα {}. Η εµβέλεια των ονοµάτων των µεταβλητών προσδιορίζεται από µερικούς βασικούς κανόνες: 1. Ονόµατα µεταβλητών ορισµένα σ ένα block έχουν τοπική (local) ισχύ, µέσα στο block αυτό. 2. Αν ένα blockπεριέχεται σ ένα άλλο (είναι δηλαδή «θυγατρικό») τότε κληρονοµεί τις µεταβλητές του «µητρικού» block. 3. Μεταβλητές που ορίζοντα έξω από οποιοδήποτε block θεωρούνται καθολικές (global) και έχουν ισχύ από το σηµείο ορισµού τους µέχρι το τέλος του πηγαίου κώδικα. 4. Μια τοπική µεταβλητή υπερισχύει µιας καθολικότερης µεταβλητής µε το ίδιο όνοµα. Ίδιοι κανόνες εµβέλειας ισχύουν και για τα άλλα προσδιοριστικα (identifiers), όπως π.χ. τα ονόµατα των συναρτήσεων. Κάθε συνάρτηση ενός προγράµµατος αποτελεί ένα block (που πιθανόν περικλείει άλλα µικρότερα block στο εσωτερικό του), εποµένως ισχύουν οι παραπάνω κανόνες. Όµως, η C++ δεν επιτρέπει τον ορισµό µιας συνάρτησης στο εσωτερικό µιας άλλης, δεν υπάρχουν δηλαδή θυγατρικές συναρτήσεις.
Εµβέλεια µεταβλητών - παράδειγµα #include <iostream> using namespace std; const double rate = 10.50; int z; void Ftwo(int a, int b, char x); void Fthree(int one, double y, int z); int main () { int num, first; double x, y, z; char name, last;... return 0; } int w; void Ftwo(int a, int b, char x) { int count;... } void Fthree(int one, double y, int z) { int a;... //BlockFour { char a;... }//end BlockFour... } Εµβέλεια των µεταβλητών στα διάφορα τµήµατα Όνοµα Ftwo Fthree BlockFour main Καθολικές: rate ΝΑΙ ΝΑΙ ΝΑΙ ΝΑΙ z ΝΑΙ ΌΧΙ ΌΧΙ ΌΧΙ w ΝΑΙ ΝΑΙ ΝΑΙ ΌΧΙ main: (function name) ΝΑΙ ΝΑΙ ΝΑΙ ΝΑΙ Τοπικές της main ΌΧΙ ΌΧΙ ΌΧΙ ΝΑΙ Ftwo: (function name) ΝΑΙ ΝΑΙ ΝΑΙ ΝΑΙ a (παράµετρος) ΝΑΙ ΌΧΙ ΌΧΙ ΌΧΙ b (παράµετρος) ΝΑΙ ΌΧΙ ΌΧΙ ΌΧΙ x (παράµετρος) ΝΑΙ ΌΧΙ ΌΧΙ ΌΧΙ Τοπικές της Ftwo ΝΑΙ ΌΧΙ ΌΧΙ ΌΧΙ Fthree: (function name) ΝΑΙ ΝΑΙ ΝΑΙ ΝΑΙ one (παράµετρος) ΌΧΙ ΝΑΙ ΝΑΙ ΌΧΙ y (παράµετρος) ΌΧΙ ΝΑΙ ΝΑΙ ΌΧΙ z (παράµετρος) ΌΧΙ ΝΑΙ ΝΑΙ ΌΧΙ Τοπικές της Fthree ΌΧΙ ΝΑΙ ΝΑΙ ΌΧΙ BlockFour : a (τοπική) ΟΧΙ ΌΧΙ ΝΑΙ ΟΧΙ
Παράδειγµα 3 - Συναρτήσεις και εµβέλεια µεταβλητών Πρόβληµα: Είναι γνωστές οι ορθογώνιες συντεταγµένες (x0,y0) ενός σηµείουτ0 και µετράται η απόσταση s και η γωνία διεύθυνσης a προς το σηµείο Τ1. Να υπολογιστούν οι ορθογώνιες συντεταγµένες (x1,y1) του T1.
Παράδειγµα 3 - Συναρτήσεις και εµβέλεια µεταβλητών
Παράδειγµα 3 - Συναρτήσεις και εµβέλεια µεταβλητών x=x0+s*sin(r); y=y0+s*cos(r); return;