====== Άσκηση 13 - procedures παράμετροι κατά αναφορά και απόκρυψη======
* Στην προηγούμενη άσκηση είδαμε την χρήση διαδικασιών (procedures) μαζί με παραμέτρους κατά τιμή
* Στην νέα Άσκηση θα δούμε
* Παραμέτρους μέσα σε procedure **κατά αναφορά**
* Τοπικές και καθολικές μεταβλητές.
* Απόκρυψη μεταβλητών.
- **ΔΗΜΙΟΥΡΓΙΑ ΕΡΓΟΥ** : Θα δημιουργήσουμε το νέο έργο **anafora**
* Κάνουμε όμοιες ενέργειες όπως στην Άσκηση1, όπου hello τώρα ο τίτλος είναι **anafora**
- **ΠΡΟΣΘΗΚΗ 1 - procedure megistos**
- Δηλώστε στο **var** 3 μεταβλητές **x,y,z**. Στο κυρίως πρόγραμμα δώστε τιμές: στην **x** τιμή **5**, στην **y** τιμή **10** και στην **z** τιμή **0**. z:=0;
x:=5;
y:=10;
- Θέλουμε να φτιάξουμε μία διαδικασία **megistos** που θα βρίσκει ποια τιμή είναι **μεγαλύτερη**, το x ή το y και **θα την βάζει στο z**. Δηλαδή στο παράδειγμά μας θα βάλει **στο z την τιμή 10**.
- Πάμε να την ορίσουμε πάνω από το **BEGIN** του κυρίως προγράμματοςprocedure megistos(a:integer; b:integer; c:integer);
begin
{εντολές υπολογισμού μέγιστου}
end;
- Μέσα στην διαδικασία **megistos** υπολογίζουμε τον μέγιστο ως εξής : **αν a>b τότε** η τιμή του **a** θα μπει στο **c**, αλλιώς η τιμή του **b** θα μπει στο **c**. Γνωρίζετε πως να το φτιάξετε.
- **ΤΡΟΠΟΠΟΙΗΣΗ 1 - πέρασμα κατά τιμή**
- Μέσα στην διαδικασία πριν τελειώσει εμφανίζουμε όλες τις μεταβλητές writeln('Μέσα στην megistos: Το a έχει τιμή ', a);
writeln('Μέσα στην megistos: Το b έχει τιμή ', b);
writeln('Μέσα στην megistos: Το c έχει τιμή ', c);
writeln('Μέσα στην megistos: Το x έχει τιμή ', x);
writeln('Μέσα στην megistos: Το y έχει τιμή ', y);
writeln('Μέσα στην megistos: Το z έχει τιμή ', z);
- Για να εκτελεστεί η διαδικασία πάμε να την καλέσουμε από το κυρίως πρόγραμμα ως εξήςmegistos(x,y,z);
- Μεταγλωττίζουμε και εκτελούμε. Στην οθόνη θα πρέπει να μας εμφανιστούν οι τιμές των μεταβλητών. Παρατηρούμε ότι μαζί με την μεταβλητή **c** **ΔΕΝ** άλλαξε και η **z**. Επίσης η procedure **megistos** βλέπει και μπορεί να εμφανίσει εκτός από τις δικές της μεταβλητές **a, b και c** και όλες τις μεταβλητές του κυρίως προγράμματος **x, y, z**. Οι μεταβλητές του κυρίως προγράμματος λέγονται **καθολικές μεταβλητές** γιατί φαίνονται και μπορούν να χρησιμοποιηθούν παντού, ακόμα και μέσα σε διαδικασίες. Κάτι βέβαια που είναι επικίνδυνο για λάθη.
- Πάμε να δούμε το ανάποδο. Μετά την κλήση της **megistos(x,y,z);** βάλτε την παρακάτω εντολή writeln('Κυρίως πρόγραμμα : Μετά την κλήση της megistos');
writeln('Κυρίως πρόγραμμα : Το z έχει τιμή ', z);
writeln('Κυρίως πρόγραμμα : Το c έχει τιμή ', c);
- Προσπαθήστε να μεταγλωττίσετε. Τι συμβαίνει. Το κυρίως πρόγραμμα δεν βλέπει την μεταβλητή **c**. Οι μεταβλητές που βρίσκονται μέσα σε διαδικασίες είναι ορατές μόνο μέσα σε αυτές τις διαδικασίες και λέγονται **τοπικές μεταβλητές**. Με αυτόν τον τρόπο παρέχουν ασφάλεια από λάθη. Αφαιρέστε την γραμμή **writeln('Κυρίως πρόγραμμα : Το c έχει τιμή ', c);** για να μεταγλωττιστεί το πρόγραμμα.
* Οπότε η τιμή που είχε το **x** δηλαδή το **5** πήγε στην μεταβλητή **a** μέσα στην διαδικασία, αντίστοιχα το **10** από το **y** πήγε στο **b** και υπολογίσαμε το μεγαλύτερο, δηλαδή το **10** που αποθηκεύτηκε στο **c**.
* Πίσω στο κυρίως πρόγραμμα το **z** είχε τιμή **0** πριν την κλήση της διαδικασίας. Την ίδια τιμή έχει και μετά την κλήση. Η διαδικασία άλλαξε την τιμή της **c** αλλά **OXI** της **z**
* Αυτή είναι και η προκαθορισμένη ασφαλής λειτουργία των διαδικασιών.
* Επειδή ένα πρόγραμμα μπορεί να σπάσει σε εκατοντάδες διαδικασίες, **δεν θέλουμε** κάθε μία από αυτές να **αλλάζει** μεταβλητές που βρίσκονται στο κυρίως πρόγραμμα. Βασικός λόγος είναι τα προγράμματα αποτελούνται από χιλιάδες γραμμές κώδικα και δεν θέλουμε 50 γραμμές κώδικα μέσα σε μία διαδικασία να επηρεάζουν χιλιάδες άλλες γραμμές κώδικα αλλάζοντας τιμές σε μεταβλητές από προγραμματιστικό σφάλμα **(bug)**.
- **ΤΡΟΠΟΠΟΙΗΣΗ 2 - πέρασμα κατά αναφορά**
* Όμως μερικές φορές είναι αναγκαίο μια διαδικασία να αλλάξει την μεταβλητή που της περάσαμε. Τότε ο ορισμός της μεταβλητής αυτής θα έχει μπροστά ένα **var**
- Αλλάξτε λοιπόν την δήλωση της διαδικασίας σε procedure megistos(a:integer; b:integer; var c:integer);
- Μεταγλωττίστε και εκτελέστε πάλι. Τι έγινε τώρα στην τιμή του z;
- **ΠΡΟΣΘΗΚΗ 2 - διαδικασία allakse**
* Θα φτιάξουμε μια νέα procedure με όνομα **allakse**. Θα παίρνει 2 μεταβλητές-ορίσματα **arithmos1** και **arithmos2**. Ο σκοπός μας είναι να βάλουμε την τιμή του **arithmos2** στην μεταβλητή **arithmos1** και την τιμή του **arithmos1** στην μεταβλητή **arithmos2**. Οπότε αν **x** ήταν **5** και **y** ήταν **10** και καλέσουμε **allakse(x,y)** το **x** να γίνει **10** και το **y** να γίνει **5**.
- Φτιάξτε την δήλωση της procedure με τις 2 παραμέτρους **arithmos1** και **arithmos2** σωστά. Σκεφτείτε εάν θα περάσουν κατά τιμή (δεν αλλάζουν) ή κατά αναφορά (αλλάζουν).
- Στο σώμα μέσα στο **begin .. end** της διαδικασίας η πρώτη σας σκέψη θα ήταν να βάλετε τον παρακάτω κώδικα : begin
arithmos1:=arithmos2;
arithmos2:=arithmos1;
end;
- Όμως προσέξτε τι θα γινόταν αν καλούσαμε με **allakse(x,y)**. O **arithmos1** αρχικά θα ήταν **5** και ο **arithmos2** **10**. Θα βάζαμε το **10** στον **arithmos1** σωστά, αλλά έτσι θα χάναμε την προηγούμενη τιμή του **arithmos1** δηλαδή το 5 που το θέλαμε για να το βάλουμε στον **arithmos2**. Η τεχνική για να το καταφέρουμε είναι να χρησιμοποιήσουμε μία επιπλέον μεταβλητή **prosorinos** ως εξής : begin
prosorinos:=arithmos1;
arithmos1:=arithmos2;
arithmos2:=prosorinos;
end;
- Μην ξεχάσετε να δηλώσετε στο **τοπικό var** της διαδικασίας **allakse** την νέα μεταβλητή **prosorinos**
- Για να δούμε τι καταφέραμε. Καλούμε στο κυρίως πρόγραμμα την διαδικασία με **allakse(x,y);** και εμφανίζσυμε μετά τις νέες τιμές των μεταβλητών **x,y**. Δοκιμάζουμε να εμφανίσουμε και την τιμή του **prosorinos**. writeln('Κυρίως πρόγραμμα : Μετά την κλήση της allakse');
writeln('Κυρίως πρόγραμμα : Το x έχει τιμή ', x);
writeln('Κυρίως πρόγραμμα : Το y έχει τιμή ', y);
writeln('Κυρίως πρόγραμμα : Το prosorinos έχει τιμή ', prosorinos);
END.
- Προσπαθήστε να μεταγλωττίσετε. Τι συμβαίνει. Το κυρίως πρόγραμμα δεν βλέπει την μεταβλητή **prosorinos**. Όπως οι μεταβλητές **arithmos1 και arithmos2** που βρίσκονται δίπλα στην δήλωση της διαδικασίας έτσι και η μεταβλητή **prosorinos** θεωρούνται **τοπικές μεταβλητές** και είναι ορατές μόνο μέσα στην ίδια διαδικασία και **ΟΧΙ** από το κυρίως πρόγραμμα. Αφαιρέστε την γραμμή **writeln('Κυρίως πρόγραμμα : Το prosorinos έχει τιμή ', prosorinos);** για να μεταγλωττιστεί το πρόγραμμα.
- **ΤΡΟΠΟΠΟΙΗΣΗ 3 - απόκρυψη μεταβλητών**
- Αλλάξτε όλο τον κώδικα της διαδικασίας **allakse** και στην θέση της βάλτε τον παρακάτω procedure allakse;
var
prosorinos : integer;
begin
prosorinos:=x;
x:=y;
y:=prosorinos;
writeln('Μέσα στην άλλαξε: Το x έχει τιμή ', x);
writeln('Μέσα στην άλλαξε: Το y έχει τιμή ', y);
end;
- Επειδή αφαιρέσαμε τις παραμέτρους, καλέστε την από το κυρίως πρόγραμμα χωρίς παραμέτρους allakse;
- Απ' ότι φαίνεται λειτουργεί. Οι μεταβλητές **x και y** μέσα στην **allakse** είναι **τοπικές ή καθολικές**; Είναι **καθολικές** βεβαίως, αφού δεν έχουν δηλωθεί μέσα στην **allakse**, αλλά στο κυρίως πρόγραμμα. Τι θα γίνει εάν τις δηλώσουμε και εκεί; Πάμε να το δούμε. Αλλάξτε την δήλωση σε **procedure allakse(x:integer; y:integer);** και καλέστε όπως πριν με **allakse(x,y);**
- Τι συνέβει; Μέσα στην **allakse** οι μεταβλητές **x και y** άλλαξαν τιμή, αλλά στο κυρίως πρόγραμμα παρέμειναν οι παλιές τιμές. Οι μεταβλητές **x και y** μέσα στην **allakse** είναι τώρα **τοπικές μεταβλητές στην allakse** και δεν έχουν σχέση με τις καθολικές **x και y** όλου του προγράμματος. Αυτό μας δίνει και την δυνατότητα να μπορούμε να ξαναχρησιμοποιούμε τα ίδια ονόματα μεταβλητών σε πολλές διαδικασίες χωρίς να μπλέκονται. Όπως μια οικογένεια μπορεί να έχει 2 παιδιά **Κώστα και Μαρία** και μία άλλη οικογένεια 2 παιδιά με τα ίδια ονόματα. Οι μεταβλητές μας είναι ακόμα **παράμετροι κατά τιμή**. **ΠΡΟΣΘΕΣΤΕ** το **var** για να τις κάνετε **παραμέτρους κατά αναφορά** ώστε να αλλάξουν και οι **καθολικές μεταβλητές x και y** στο κυρίως πρόγραμμα.
* ΠΡΟΣΟΧΗ! Εδώ έχουμε τις **τοπικές μεταβλητές x και y της allakse** που δείχνουν **στην ίδια θέση μνήμης** με τις **καθολικές μεταβλητές x και y του κυρίως προγράμματος**. **Διαφορετικές** μεταβλητές που επειδή προσθέσαμε το var δείχνουν και αλλάζουν **στην ίδια θέση μνήμης**.
* Τα ίδια ισχύουν και για την **τοπική μεταβλητή prosorinos**. Εάν είχαμε ορίσει και μία **καθολική μεταβλητή prosorinos** στο κυρίως πρόγραμμα, μέσα στην **allakse** δεν θα την βλέπαμε, αφού θα βλέπαμε την **τοπική μεταβλητή prosorinos**.
* Αυτό που είδαμε λέγεται **απόκρυψη καθολικών μεταβλητών**.
----
* **ΕΠΕΚΤΑΣΗ 1 / ΑΣΚΗΣΗ ΓΙΑ ΤΟ ΣΠΙΤΙ**
-
* **ΕΠΕΚΤΑΣΗ 2 / ΑΣΚΗΣΗ ΓΙΑ ΤΟ ΣΠΙΤΙ**
-