Άσκηση 13 - procedures παράμετροι κατά αναφορά και απόκρυψη

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