Κλήση Συναρτήσεων ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΕΩΝ. Γεώργιος Παπαϊωάννου ( )

Σχετικά έγγραφα
Προγραμματισμός Υπολογιστών με C++

Προγραμματισμός Υπολογιστών με C++

Προγραμματισμός Υπολογιστών με C++

ΔΕΙΚΤΕΣ ΚΑΙ ΔΙΕΥΘΥΝΣΕΙΣ

Δομημένος Προγραμματισμός

ΒΑΣΙΚΟΙ ΤΥΠΟΙ ΚΑΙ ΠΙΝΑΚΕΣ

Προγραμματισμός Υπολογιστών με C++

Αντικειμενοστραφείς Γλώσσες Προγραμματισμού C++ / ROOT

Προγραμματισμός Ι. Δείκτες. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Προγραμματισμός Ι (ΗΥ120)

Λύβας Χρήστος Αρχική επιµέλεια Πιτροπάκης Νικόλαος και Υφαντόπουλος Νικόλαος

Συναρτήσεις και Πίνακες

ΚΑΤΑΣΚΕΥΑΣΤΕΣ ΑΝΤΙΓΡΑΦΗΣ

Προγραμματισμός Υπολογιστών με C++

Αναφορές, είκτες και Αλφαριθμητικά

Προγραμματισμός Υπολογιστών με C++

Η γλώσσα προγραμματισμού C Οι συναρτήσεις στη C (2)

Προγραμματισμός Ι. Κλάσεις και Αντικείμενα. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Προγραμματισμός Ι. Δυναμική Διαχείριση Μνήμης. Δημήτρης Μιχαήλ. Ακ. Έτος Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα Αναφορές

Εισαγωγή στον Προγραμματισμό με C++

10 η Διάλεξη C++ - Πίνακες. Δρ. Χρήστος Δρόσος ΑΕΙ ΠΕΙΡΑΙΑ ΤΤ ΤΜΗΜΑ ΑΥΤΟΜΑΤΙΣΜΟΥ

Υπερφόρτωση τελεστών

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Αναφορές Στοίβα και Σωρός Μνήμης Αντικείμενα ως ορίσματα

Προγραμματισμός Η/Υ (ΤΛ2007 )

Η γλώσσα προγραμματισμού C Οι συναρτήσεις στη C (2)

Αντικειμενοστραφείς Γλώσσες Προγραμματισμού C++ / ROOT

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Αναφορές Στοίβα και Σωρός Αναφορές-Παράμετροι

Διαδικασιακός Προγραμματισμός

Τίτλος Μαθήματος: Ηλεκτρονικοί Υπολογιστές IΙΙ. Διδάσκων: Επίκουρος Καθηγητής Αθανάσιος Σταυρακούδης

Προγραμματισμός Ι. Συναρτήσεις. Πανεπιστήμιο Πελοποννήσου Τμήμα Πληροφορικής & Τηλεπικοινωνιών

Α. unsigned int Β. double. Γ. int. unsigned char x = 1; x = x + x ; x = x * x ; x = x ^ x ; printf("%u\n", x); Β. unsigned char

Πίνακες: μια σύντομη εισαγωγή. Πίνακες χαρακτήρων: τα "Αλφαριθμητικά"

Στοιχειώδης προγραμματισμός σε C++

Α Β Γ static; printf("%c\n", putchar( A +1)+2); B DB BD. int i = 0; while (++i); printf("*");

Ανάπτυξη και Σχεδίαση Λογισμικού

Προγραμματισμός Η/Υ (ΤΛ2007 )

Τελεστές ΤΕΛΕΣΤΕΣ. Γεώργιος Παπαϊωάννου ( )

Προγραμματισμός Η/Υ (ΤΛ2007 )

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Αναφορές Αντικείμενα ως ορίσματα

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Συναρτήσεις I Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Εισαγωγή ΕΙΣΑΓΩΓΗ. Γεώργιος Παπαϊωάννου ( )

Διδάσκων: Κωνσταντίνος Κώστα Διαφάνειες: Δημήτρης Ζεϊναλιπούρ

Διαδικασιακός Προγραμματισμός

Προγραμματισμός Υπολογιστών με C++

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Δομή του προγράμματος. Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Οντοκεντρικός Προγραμματισμός

Προγραμματισμός Υπολογιστών με C++

Διάλεξη 3η: Τύποι Μεταβλητών, Τελεστές, Είσοδος/Έξοδος

Δομημένος Προγραμματισμός (ΤΛ1006)

Διάλεξη 11η: Δείκτες, μέρος 1

#include <stdlib.h> Α. [-128,127] Β. [-127,128] Γ. [-128,128]

Διάλεξη 5: Δείκτες και Συναρτήσεις

Δομημένος Προγραμματισμός. Τμήμα Επιχειρηματικού Σχεδιασμού και Πληροφοριακών Συστημάτων

Δομημένος Προγραμματισμός (ΤΛ1006)

Η γλώσσα προγραμματισμού C

Εισαγωγή στον Προγραμματισμό

Η γλώσσα προγραμματισμού C

3ο σετ σημειώσεων - Πίνακες, συμβολοσειρές, συναρτήσεις

Δομημένος Προγραμματισμός

ΔΟΜΗΜΕΝΟΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ

Συμβολοσειρές ΣΥΜΒΟΛΟΣΕΙΡΕΣ. Γεώργιος Παπαϊωάννου ( )

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Πίνακες Κλάσεις και Αντικείμενα

Συναρτήσεις (Functions) Εισαγωγή στη C++

Δείκτες (Pointers) Ένας δείκτης είναι μια μεταβλητή με τιμή μια διεύθυνση μνήμης. 9.8

Γ7.2 Συμβολοσειρές (Strings) Γ Λυκείου Κατεύθυνσης

int array[10]; double arr[5]; char pin[20]; Προγραµµατισµός Ι

Αντικειμενοστραφής Προγραμματισμός

Προγραμματισμός Υπολογιστών με C++

Η βασική συνάρτηση προγράμματος main()

Εισαγωγή στον Προγραμματισμό

ΥΠΟΛΟΓΙΣΤΕΣ ΙΙ. Τι είναι ; Συναρτήσεις. Παράδειγμα #1. double convert ( double cm ) { double inch;

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΥΠΟΛΟΓΙΣΤΩΝ & ΥΠΟΛΟΓΙΣΤΙΚΗ ΦΥΣΙΚΗ

Διάλεξη 15η: Αναδρομή, μέρος 1ο

Εισαγωγή στους Η/Υ. Γιώργος Δημητρίου. Μάθημα 3-4: Προγραμματισμός MIPS. Πανεπιστήμιο Θεσσαλίας - Τμήμα Πληροφορικής

Γλώσσα Προγραμματισμού C++ Εισαγωγή - Μια πρώτη ματιά

Ηβασικήσυνάρτηση προγράμματος main()

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ II. Υφαντόπουλος Νικόλαος Υποψήφιος Διδάκτορας Contact:

ΑΣΚΗΣΗ 6: ΔΕΙΚΤΕΣ. Σκοπός της Άσκησης. 1. Εισαγωγικά στοιχεία για τους Δείκτες

Προγραμματισμός Υπολογιστών & Υπολογιστική Φυσική

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Αντικείμενα με πίνακες. Constructors. Υλοποίηση Στοίβας

ΣΤΟΙΧΕΙΑ ΤΗΣ ΓΛΩΣΣΑΣ C++ Constructors, Destructors, Pointers IO Streams, File Streams

Διαδικασιακός Προγραμματισμός

ΣΥΝΑΡΤΗΣΕΙΣ Παραδείγματα χρήσης συναρτήσεων

Προγραµµατιστικές Τεχνικές

5. ΣΥΝΑΡΤΗΣΕΙΣ. (Πρόχειρο σχέδιο - Μαθήµατος 3) p Συναρτήσεις, που δεν επιστρέφουν κάποια τιµή

Διαδικασιακός Προγραμματισμός

ΗΥ-150. Πίνακες (Arrays)

ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΗΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ

Διαδικαστικός Προγραμματισμός

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα Constructors, equals, tostring

Ανάπτυξη και Σχεδίαση Λογισμικού

Κλάσεις και αντικείμενα #include <iostream.h<

Μεθόδων Επίλυσης Προβλημάτων

Διαδικασιακός Προγραμματισμός

Προγραμματισμός Συστημάτων

ΕΡΓΑΣΤΗΡΙΟ 9: Συμβολοσειρές και Ορίσματα Γραμμής Εντολής

Προγραμματισμός Η/Υ (ΤΛ2007 )

Η γλώσσα προγραμματισμού C Δυναμική διαχείριση μνήμης

Προγραμματισμός Ι. Προχωρημένα Θέματα. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Transcript:

ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΕΩΝ Γεώργιος Παπαϊωάννου (2013-16) gepap@aueb.gr

Περιγραφή: Μορφές μεταβίβασης ορισμάτων σε συναρτήσεις (και μεθόδους) και οι επιπτώσεις τους Επιστροφή τιμών από κλήση συναρτήσεων Υπερφόρτωση συναρτήσεων Τελευταία ενημέρωση: Οκτώβριος 2016 Εισαγωγή - 2

Υπάρχουν 2 τρόποι στη C/C++ να περάσουμε ένα όρισμα σε συνάρτηση/μέθοδο: Κατά τιμή (by value) Με αναφορά (by reference) 3

Σε αυτό τον τρόπο μεταβίβασης ορίσματος που τον γνωρίζεται και από τη Java (δεν έχει η Java άλλον τρόπο), η μεταβλητή που περνάμε αντιγράφεται στο όρισμα της συνάρτησης (και άρα σε μια μεταβλητή στη στοίβα κλήσεων) Αν τροποποιήσουμε το όρισμα μέσα στη συνάρτηση, η αλλαγή χάνεται όταν επιστρέψουμε από αυτή 4

int incr(int arg) { arg++; return arg; // To arg είναι ακέραια μεταβλητή. // Αυξάνει τη μεταβλητή στην οποία // Επιστρέφει τη νέα τιμή της μεταβλητής. int main() { int i = 1, j = 0; j = incr(i); // Αλλάζει μόνο το j. cout << i << ", " << j; // Τυπώνει «1, 2". 5

int incr(int *arg) { // To arg είναι δείκτης σε ακέραια μεταβλητή. *arg++; // Αυξάνει το περιεχόμενο του δείκτη // Προσοχή: εδώ αντιγράφεται ο δείκτης (τιμή της // arg: η διεύθυνση που δείχνει), άρα // αλλάζοντας το περιεχόμενο του δείκτη, η // αλλαγή ισχύει και μετά την έξοδο της συνάρτησης return *arg; // Επιστρέφει τη νέα τιμή. int main() { int i = 1, j = 0; int * p_i = &i; j = incr(p_i); // Αλλάζει και το i και το j. cout << i << ", " << j; // Τυπώνει 2, 2. 6

Όταν περνάμε διεύθυνση ή πίνακα (δηλ. διεύθυνση του πρώτου στοιχείου) ως όρισμα, η τιμή που αντιγράφεται είναι ο δείκτης, δηλαδή η μεταβλητή που κρατάει τη διεύθυνση: &i 0x16F0 0x16F4 0x16F8 int i = 1, j = 0; p_i = &i; j = incr(&i); i (1) j (0) p_i (0x16F0) int incr(int *arg) { *arg++; return *arg 0x16F0 0x16F4 0x16F8 i (1) j (0) p_i (0x16F0) 0x1AEC arg (0x16F0) 7

Είδαμε ότι μπορούμε να μεταβάλουμε τιμές που δίνουμε σε συναρτήσεις, περνώντας τες με δείκτη σε αυτές ως όρισμα Υπάρχει άλλος τρόπος; Ναι, γιατί στη C/C++ μπορούμε επιπλέον να περάσουμε ένα όρισμα με αναφορά Ένα όρισμα που μεταβιβάζεται με αναφορά, παίρνει το σύμβολο & πριν το όνομα της παραμέτρου 8

int incr(int& arg) { arg++; return arg; // To arg είναι αναφορά σε ακέραια // μεταβλητή. / Το arg είναι τοπική αναφορά, αλλά // αναφέρεται στο i της main. // Αυξάνει τη μεταβλητή στην οποία // αναφέρεται το arg. // Επιστρέφει τη νέα τιμή της μεταβλητής. int main() { int i = 1, j = 0; j = incr(i); // Αλλάζει και το j και το i. cout << i << ", " << j; // Τυπώνει "2, 2". 9

Η διαφορές τους είναι ελάχιστες: Επί της ουσίας έχουμε τις ίδιες δυνατότητες ενημέρωσης του ορίσματος Στο πέρασμα με αναφορά δε χρειάζεται να ελέγξουμε το όρισμα αν είναι nullptr (δε γίνεται να είναι, γιατί ΔΕΝ περνάμε δείκτη αλλά μια υπαρκτή μεταβλητή) Μια αναφορά που περνάμε ως όρισμα συνήθως υλοποιείται ως δείκτης από το μεταγλωττιστή, αλλά υπάρχει ενδεχόμενο να γίνουν επιπρόσθετες βελτιστοποιήσεις Μια τοπική μεταβλητή τύπου αναφοράς συνήθως απλά εξαλείφεται και αποτελεί απλά ψευδώνυμο στην μεταβλητή που αναφέρεται 10

C/C++ Java Μπορώ να περάσω ορίσματα τόσο με αντιγραφή τιμής (by value) όσο και με αναφορά (by reference) Χρησιμοποιούμε την έννοια της μεταβίβασης δείκτη, εναλλακτικά με το πέρασμα με αναφορά Περνάω όλα τα ορίσματα μόνο ως τιμές (by value) Όλα τα αντικείμενα εκτός από τους βασικούς τύπους, δεσμεύονται στο σωρό και μας επιστρέφεται μια «αναφορά» (δηλ. δείκτης!) Οπότε όταν περνάμε: void Method(Object data), στην ουσία το Object είναι δείκτης στο δεσμευμένο χώρο του αντικειμένου που τον περνάμε by value Εισαγωγή - 11

Μια αναφορά είτε μετατρέπεται από τον compiler σε δείκτη είτε αντικαθίσταται από τη μεταβλητή που αναφέρεται, κατά τη μεταγλώττιση Ο δείκτης είναι πάντα απλά μια διεύθυνση Ο δείκτης μπορεί να πάρει τιμή NULL, ενώ η αναφορά για τον προγραμματιστή έχει την έννοια του ψευδώνυμου (ταύτισης) με άλλη μεταβλητή και άρα δεν μπορεί να μην έχει έγκυρη τιμή 12

Κατά τη μεταβίβαση μεγάλων δομών δεδομένων, η μεταβίβαση κατά τιμή είναι αργή,γιατί αντιγράφει τις δομές. int myfun(vector<int> v); Κατά τιμή. Αργό. Π.χ. κατά την κλήση myfun(somevector), το τοπικό vector v της myfun γίνεται αρχικά αντίγραφο του somevector (δεσμεύεται χώρος και καλείται ο κατασκευαστής αντιγραφής!). Πρέπει να αντιγραφούν όλα τα περιεχόμενα του somevector στο v. Στη μεταβίβαση κατά αναφορά (με χρήση δεικτών ή αναφορών) αντιγράφεται μόνο η διεύθυνση της δομής, πιο γρήγορο. int myfun(vector<int>& v); // Κατά αναφορά. Γρήγορο. Π.χ. κατά την κλήση myfun(somevector), η τοπική αναφορά v της myfun γίνεται απλά ψευδώνυμο (εδώ δείκτης) του somevector. 13

Όταν περνάμε ορίσματα κατά τιμή (by value), έτσι κι αλλιώς δε μπορούμε να μεταβάλουμε τη μεταβλητή που περάσαμε γιατί την αντιγράφουμε σε νέα Όταν περνάμε όμως όρισμα με αναφορά, μπορούμε να μεταβάλουμε τη μεταβλητή που περάσαμε Μπορούμε να απαγορεύσουμε την αλλαγή του ορίσματος με αναφορά, αν δηλώσουμε το όρισμα ως σταθερό (const): Π.χ int myfun(const int & v); 14

int myfun(vector<int>& v); Κατά αναφορά. Γρήγορο, αλλά π.χ. κατά την κλήση myfun(somevector) έχει η myfun τη δυνατότητα να αλλάξει τα περιεχόμενα του somevector. int myfun(const vector<int>& v); Κατά αναφορά. Γρήγορο και π.χ. κατά την κλήση myfun(somevector) δεν μπορεί η myfun να αλλάξει τα περιεχόμενα του somevector. Με μεγάλες δομές δεδομένων, αντί για μεταβίβαση κατά τιμή χρησιμοποιήστε μεταβίβαση με αναφορά (με δείκτες ή αναφορές) Χρησιμοποιήστε το const αν θέλετε να εξασφαλίσετε ότι η καλούμενη συνάρτηση δεν θα μπορεί να αλλάξει αυτό που της μεταβιβάζουμε ως όρισμα Δεν έχει νόημα για πέρασμα by value! 15

void f(string& arg) { cout << arg; void g(const string& arg) { // Υπόσχεται να μην αλλάξει το όρισμα. cout << arg; int main() { string s1 = "hello"; // Το s1 μπορεί να αλλάξει. const string s2 = "world"; // Το s2 δεν μπορεί να αλλάξει. f(s1); // OK. f(s2); // Λάθος. Η f δεν εγγυάται ότι δεν θα // αλλάξει το s2. g(s1); g(s2); // OK και τα δύο. g(s1 + s2); // Δημιουργείται προσωρινή σταθερά const string // για το άθροισμα, που μεταβιβάζεται κατά αναφορά. f(s1 + s2); // Λάθος. Δεν εγγυάται ότι δεν θα αλλάξει την // προσωρινή σταθερά του αθροίσματος. 16

Στα ορίσματα συναρτήσεων, int arg[] και int* arg είναι ισοδύναμα. (Το ίδιο για float arg[] και float* arg κλπ.) X void incr(int arg[3], int size); // Δεν επιτρέπεται. void incr(int arg[], int size); // Tο ίδιο με το ακόλουθο: void incr(int* arg, int size); 17

int main() { int myarray[] = {1, 2, 3; incr(myarray, 3); // Το myarray χρησιμοποιείται ως δείκτης. // Κατά την κλήση της incr, ο arg δείχνει εκεί που δείχνει ο // myarray, δηλαδή δείχνει στην αρχή του πίνακα myarray. for(int i = 0; i < 3; i++) { cout << myarray[i] << endl; // Τυπώνει «2, 3, 4». void incr(int* arg, int size) { // Το arg δείχνει στην πρώτη θέση // του myarray της main. for(int i = 0; i < size; i++) { arg[i]++; // Αλλάζει τον πίνακα της main. // Χρειάζεται να περνάμε το μέγεθος // του πίνακα, αλλιώς δεν το έχουμε 18

#include <iostream> using namespace std; Αριθμός ορισμάτων που περνάμε στο πρόγραμμα, συμπεριλαμβανόμενου και του ίδιου του ονόματος του εκτελέσιμου int main( int argc, char* argv[] ) { // ή char** argv for(unsigned i = 0; i < argc; i++) { cout << argv[i] << endl; Ένας δείκτης σε πίνακα χαρακτήρων για κάθε λέξη της γραμμής εντολών. Ο πίνακας χαρακτήρων περιέχει την αντίστοιχη λέξη. Πρώτη λέξη θεωρείται το όνομα του προγράμματος. 19

γραμμή εντολών: > myprog.exe first second «πίνακας με πίνακες χαρακτήρων» Άρα: argv argc = 3 char* argv[] Ισοδύναμα: char** argv (δείκτης σε char) (δείκτης σε char) (δείκτης σε char) 's' 'e' 'c' 'o' 'n' 'd' '\0' 'f' 'i' 'r' 's' 't' '\0' 'm' 'y' 'p' 'r' 'o' 'g' '\0' 20

int f(int& arg) { arg++; return arg; // Το arg θα αναφέρεται στο i της main. // Αυξάνει αυτό στο οποίο αναφέρεται το arg. // Επιστρέφει την τιμή του i της main. int main() { int i = 1; f(i); // i = 2. Η τιμή που επιστρέφεται (2) αγνοείται. int j = f(i); // i = 3. Η επιστρεφόμενη τιμή (3) αποθηκεύεται στο j. i++; // i = 4. cout << j << << i << endl; // Τυπώνει 3 4. cout << f(i) << endl; // Τυπώνει 5. // f(i) = 10; // Δεν επιτρέπεται. Για τον ίδιο // λόγο που δεν επιτρέπεται το 6=10 21

int& g(int& arg) { // Το arg θα αναφέρεται στο i της main. arg++; // Αυξάνει αυτό στο οποίο αναφέρεται το arg. return arg; Δεν είναι καλή πρακτική να επιστρέφουμε αναφορές Προσοχή: ΠΟΤΕ δεν επιστρέφω αναφορά σε τοπικές μεταβλητές της συνάρτησης ή μεθόδου! Οι μεταβλητές αυτές παύουν να ισχύουν (δεσμεύονται στη στοίβα, όχι στο σωρό) μετά την έξοδο από τη συνάρτηση και άρα οι διεύθυνση της αναφοράς είναι άκυρη. 22

int main() { int i = 1; int& ref = i; // Αναφορά στο i. g(i); // i = 2. Το g(i) δεν χρησιμοποιείται int j = ref; // Το j παίρνει την τιμή του i, δηλαδή j = 2 j = g(i); // i = 3. To j παίρνει την τιμή του i, δηλαδή 3 int& r = g(i); // i = 4. To r αναφέρεται σε αυτό στο οποίο // αναφέρεται και το g(i), δηλαδή αναφορά στο i. int& r2 = f(i); // Δεν επιτρέπεται r++; cout << i << endl; // i = 5. Τυπώνει 5. cout << g(i) << endl; // i = 6, τυπώνει 6 g(i) = 10; // i = 7, αλλά αμέσως μετά i = 10, γιατί // το g(i) είναι αναφορά στο i. 23

Κυρίως χρησιμοποιείται όταν δημιουργώ ένα νέο δεδομένο που θέλω να επιστρέψω μέσα στο σώμα μιας συνάρτησης, δεσμεύοντας μια μεταβλητή από το σωρό: float * CreateRampSequence(size_t elements) { float * data = new float[elements] (); for (size_t i = 0; i<elements; i++ ) data[i] = i; return data; ΔΕΝ επιστρέφω δείκτες σε διευθύνσεις τοπικών μεταβλητών! Δεν ξεχνώ ότι πρέπει έξω από τη συνάρτηση σε κάποιο σημείο να αποδεσμεύσω τη μνήμη με delete[] 24

Επειδή δε γνωρίζω από την υπογραφή της συνάρτησης αν η μνήμη δεσμεύτηκε με new ή με new[] (ως πίνακας), είναι κομψότερο, σε τέτοιες περιπτώσεις να παρέχω και αντίστοιχες συναρτήσεις αποδέσμευσης: void ReleaseSequence(float * data) { if (data!= nullptr) delete[] data; Βοηθάει κάποιον που θα χρησιμοποιήσει τον κώδικα να μην κάνει λάθη 25

Στη δήλωση μιας συνάρτησης / μεθόδου μπορούμε να προσδιορίσουμε «default» τιμές για ορίσματα: void print(int i, const string& s = "the value is: "); int main() { int i = 5; print(i, "i = "); // Τυπώνει «i = 5». print(i); // Τυπώνει «the value is: 5». // Ορισμός της συνάρτησης. Η προκαθορισμένη τιμή // δίνεται στη δήλωση, όχι εδώ: void print(int i, const string& s) { printf( %s%i\n, s.c_str(), i); 26

void g(int i, int j = 0, float f = 1.0f); Αν προκαθορίσω τιμή για ένα όρισμα, πρέπει να ορίσω το κάνω και για όλα τα ορίσματα δεξιά του. X void g(int i, int j = 0, float f); // Λάθος. Πρέπει να ορίσω προκαθορισμένη τιμή και για το f. 27

void print(float f); // Για τύπωμα float. void print(string s); // Για τύπωμα string. void print(float arg[], unsigned size); // Τύπωμα πίνακα float. int main() { float f = 5.0F; int i = 10; string s = "test"; float arr[] = {1.0F, 2.0F, 3.0F; print(f); // Χρησιμοποιείται η πρώτη μορφή. print(s); // Χρησιμοποιείται η δεύτερη μορφή. print(arr, 3); // Χρησιμοποιείται η τρίτη μορφή. print(i); // Χρησιμοποιείται η πρώτη μορφή μετά // από μετατροπή του i σε float. 3 ξεχωριστοί ορισμοί για τις μορφές της print() 28

void print(float f) { cout << f << endl; void print(string s) { cout << s << endl; void print(float arg[], unsigned size) { for(unsigned i = 0; i < size; i++) { printf( %f, arg[i]); printf( \n ); 29

void f(int i); int f(int i); // Οι μορφές δεν μπορούν να διαφέρουν // μόνο στον τύπο επιστροφής. void g(string s); void g(string& s); // Δε θεωρείται αρκετή η διαφορά μεταξύ // τύπου και αναφοράς στον ίδιο τύπο. void h(string& s); // Αν έχουν οριστεί και οι δύο, void h(const string& s); // Χρησιμοποιείται η 2η μορφή όταν μεταβιβάζονται σταθερές και η // 1η μορφή όταν μεταβιβάζονται μη σταθερές. 30

Όταν μια συνάρτηση δηλωθεί inline, τότε αντί να κληθεί, ο κώδικάς της ενσωματώνεται στο σημείο της κλήσης Δε δημιουργείται νέο stack frame Δεν έχουμε το κόστος της κλήσης της συνάρτησης (πρόλογος/επίλογος, πέρασμα και αντιγραφή δεδομένων) Δε μπορούμε να έχουμε inline αναδρομικές συναρτήσεις Ο κώδικας μεγαλώνει, γιατί σε κάθε σημείο που θα γινόταν κλήση της συνάρτησης, επαναλαμβάνεται ο κώδικάς της Οι μεταγλωττιστές, συνήθως βάζουν αυτόματα inline κάποιες (συνήθως μικρές) συναρτήσεις σαν βελτιστοποίηση 31

void print(int arg) { cout << "value: " int main() { << arg; inline void print(int arg) { cout << "value: " << arg; int main() { int i = 10; print(i); { int arg = i; cout << "value:" << arg; int i = 10; print(i); i = 20; print(i); i = 20; print(i); { int arg = i; cout << "value:" << arg; 32