ΚΕΝΤΡΟ ΠΛΗ.ΝΕ.Τ. Ν. ΦΛΩΡΙΝΑΣ
Η Γλώσσα Προγραμματισμού Pascal
Εισαγωγή στην Pascal
Η Pascal είναι μια γλώσσα προγραμματισμού υψηλού επιπέδου (high-level programming language), που αναπτύχθηκε από τον Niklaus Wirth στα τέλη της δεκαετίας του 1960. Η γλώσσα πήρε το όνομά της από τον επιστήμονα Blaise Pascal, έναν Γάλλο μαθηματικό του 17ου αιώνα, ο οποίος κατασκεύασε μια από τις πρώτες μηχανές άθροισης και έβαλε έτσι, ίσως άθελά του, το δικό του λιθαράκι στην ιστορία των υπολογιστικών μηχανών και κατ’ επέκταση των υπολογιστών.
Η Pascal είναι περισσότερο γνωστή ως μια από τις πιο κατάλληλες γλώσσες προγραμματισμού για τη διδασκαλία των τεχνικών του δομημένου προγραμματισμού (structured programming techniques). Είναι τέτοια η φύση της γλώσσας που αναγκάζει τους προγραμματιστές να σχεδιάσουν τα προγράμματά τους μεθοδικά και προσεκτικά. Για τον λόγο αυτόν, είναι ιδιαίτερα δημοφιλής για διδασκαλία. Η Pascal σχεδιάσθηκε αρχικά για διδασκαλία και είναι ακόμα κατάλληλη γι’ αυτή τη δουλειά.
Αν μάθετε την Pascal, τότε οι περισσότερες από τις υπόλοιπες γλώσσες προγραμματισμού θα σας φανούν οικείες. Η Pascal χρησιμοποιεί τέτοια πρότυπα (standards), που κάνει εύκολο το γράψιμο των προγραμμάτων. Η Turbo Pascal αποτελεί μια δημοφιλή παραλλαγή (έκδοση, version) της Pascal, που δημιουργήθηκε από την εταιρεία Borland/Inprise Inc.
Η C και η Pascal θεωρούνται γλώσσες προγραμματισμού υψηλού επιπέδου (high level programming languages). Χρησιμοποιούν εντολές που μας θυμίζουν την αγγλική γλώσσα και οι οποίες μετατρέπονται σε εντολές γλώσσας μηχανής όταν εκτελούνται στους υπολογιστές. Τα προγράμματα που γράφουμε σε C και Pascal είναι απλά αρχεία κειμένου (text files) που περιέχουν εντολές προγραμματισμού και μπορούμε να τα δημιουργήσουμε μ’ έναν απλό επεξεργαστή κειμένου (text editor), ή, ακόμα καλύτερα, με τους ενσωματωμένους επεξεργαστές κειμένου που διαθέτουν οι γλώσσες αυτές.
Το πρόγραμμα που γράφουμε αποκαλείται πηγαίο πρόγραμμα (source program), το οποίο είναι κατανοητό από εμάς αλλά όχι και από τον υπολογιστή, ο οποίος αναγνωρίζει μόνο το μεταγλωττισμένο ή αντικείμενο πρόγραμμα (object program), που είναι το ίδιο πρόγραμμα σε γλώσσα μηχανής.
Γιατί Πρέπει να Μάθουμε την Pascal
Η Pascal παραμένει πάντα μια πολύ χρήσιμη γλώσσα, ιδιαίτερα κατάλληλη για διδασκαλία. Οι C και C++ είναι πολύ συμβολικές γλώσσες, δηλ. ενώ η Pascal χρησιμοποιεί κανονικές αγγλικές λέξεις, όπως για παράδειγμα τις begin και end, οι C/C++ χρησιμοποιούν σύμβολα, όπως { και }. Επίσης, ενώ οι C and C++ δεν είναι πολύ αυστηρές στους τύπους δεδομένων που χρησιμοποιούν, στην Pascal η ανάμειξη των τύπων δεδομένων συχνά προκαλεί λάθος. Αντίθετα, στις C/C++, τίποτα δεν συμβαίνει.
Η Pascal θυμίζει πολύ την αγγλική γλώσσα στις δομές της. Αυτό περιλαμβάνει και τη χρήση λέξεων (words), που είναι σειρές (strings) χαρακτήρων που αναγνωρίζουν στοιχεία μέσα στο πρόγραμμα. Υπάρχουν πολλά διαφορετικά είδη λέξεων για την αναγνώριση μεταβλητών (variables), προγραμμάτων (programs) και υποπρογραμμάτων (subprograms), που είναι περισσότερα γνωστά ως διαδικασίες (procedures) και συναρτήσεις (functions).
Υπάρχει βέβαια και μια λίστα από λέξεις που έχουν μια συγκεκριμένη χρήση και τις οποίες δεν μπορεί να αλλάξει ο προγραμματιστής. Αυτές είναι γνωστές ως δεσμευμένες λέξεις (reserved words).
Τα Βασικά Συστατικά ενός Προγράμματος της Pascal
Το κάθε πρόγραμμα που γράφουμε σε Pascal αποτελείται από τα εξής τρία συστατικά :
Επικεφαλίδα προγράμματος (Program heading) : program identifier(input, output); Είναι πιθανώς το μοναδικό αναγνωριστικό (identifier) που το γράφουμε μία μόνο φορά και με μήκος έως 64 χαρακτήρες. Άρα, μπορούμε να το κάνουμε να είναι αρκετά περιγραφικό.
Τμήμα δηλώσεων (Declaration section) : var const. Πρόκειται για μεταβλητές και σταθερές που τις δηλώνουμε εδώ και που θα τις χρησιμοποιήσουμε αργότερα στο πρόγραμμά μας. Εδώ δεν γίνεται καμία ενέργεια, αλλά απλά ενημερώνουμε την Turbo Pascal για το τι μεταβλητές και σταθερές θα χρειασθούμε αργότερα μέσα στο κυρίως πρόγραμμα.
Εκτελέσιμο τμήμα (Executable section) : begin ... end. Βλέπουμε ότι η λέξη end ακολουθείται από μια τελεία, που υποδηλώνει και το τέλος ενός προγράμματος της Pascal. Ανάμεσα στα begin και end βρίσκονται όλες οι εντολές του προγράμματος, οι οποίες μπορούν να κάνουν εργασίες όπως λήψη (διάβασμα) στοιχείων, τροποποίησή τους και εμφάνισή τους (εκτύπωση) στην οθόνη (screen) ή στον εκτυπωτή (printer).
Οι Εκτελέσιμες Εντολές
Μια εκτελέσιμη εντολή (executable statement) αποτελείται από έγκυρα αναγνωριστικά (identifiers), δεσμευμένες λέξεις (reserved words), αριθμούς ή/και χαρακτήρες με την κατάλληλη στίξη. Κατά μια άποψη, μια εκτελέσιμη εντολή θυμίζει πολύ μια φράση μέσα σε μια πρόταση. Η κάθε εκτελέσιμη εντολή πρέπει να τερματίζει με τον χαρακτήρα ; (semicolon). Υπάρχει μία μόνο εξαίρεση σ’ αυτόν τον κανόνα όταν η εντολή ακολουθείται από τη δεσμευμένη λέξη END.
Η Turbo Pascal δεν απαιτεί από τις εκτελέσιμες εντολές να χωρίζονται με αλλαγές γραμμών αλλά μόνο η παρουσία του χαρακτήρα ; είναι απαραίτητη για να μπορούν να ξεχωρίζουν οι εντολές. Κάτι άλλο πολύ βασικό που πρέπει να τηρούμε είναι οι εσοχές (indentation) στις δομές των εντολών. Οι εσοχές δεν σημαίνουν τίποτα για την Pascal αλλά είναι πολύ βασικές για να μπορούμε να καταλάβουμε τον τρόπο λειτουργίας ενός προγράμματος.
Ο Μεταγλωττιστής (Compiler) της Pascal
Ο υπολογιστής δεν μπορεί να κατανοήσει την ομιλούμενη ή τη γραπτή γλώσσα που χρησιμοποιούν οι άνθρωποι στις καθημερινές τους συνομιλίες και από την άλλη μεριά οι άνθρωποι δεν είναι σε θέση να κατανοήσουν τη δυαδική γλώσσα που χρησιμοποιεί ο υπολογιστής για να κάνει τις εργασίες του. Είναι συνεπώς απαραίτητο να γράψουμε τις εντολές (οδηγίες) μας σε μια ειδικά ορισμένη γλώσσα, όπως είναι η Pascal για παράδειγμα, την οποία μπορούμε να κατανοήσουμε, και μετά να την μετατρέψουμε σ’ έναν λιτό κώδικα (γλώσσα μηχανής) που μόνο ο υπολογιστής μπορεί να καταλάβει.
Ένας μεταγλωττιστής (compiler) της Pascal είναι και ο ίδιος ένα πρόγραμμα υπολογιστή που η μόνη δουλειά του είναι να μετατρέπει ένα πρόγραμμα της Pascal από τη μορφή που μπορεί να κατανοήσει ο άνθρωπος σε μια μορφή που μόνο ο υπολογιστής μπορεί να διαβάσει και να εκτελέσει. Ο υπολογιστής προτιμά τις σειρές από τα δυαδικά ψηφία 0 και 1, τα οποία δεν σημαίνουν τίποτα για μας αλλά που μπορούν να τύχουν μιας πολύ γρήγορης επεξεργασίας από τον υπολογιστή.
Το αρχικό πρόγραμμα που γράφουμε σε Pascal αποκαλείται ο πηγαίος κώδικας (source code) και ο προκύπτον μεταγλωττισμένος κώδικας που δημιουργείται από τον μεταγλωττιστή (compiler) αποκαλείται συχνά ένα αντικείμενο αρχείο (object file).
Ένα ή περισσότερα αντικείμενα αρχεία (object files) μπορούν να συνδυαστούν με κάποιες προκαθορισμένες βιβλιοθήκες (libraries) από ένα άλλο πρόγραμμα που αποκαλείται linker ή και binder, για να δημιουργηθεί έτσι το τελικό ολοκληρωμένο αρχείο (εκτελέσιμο αρχείο – executable file), το οποίο και μπορεί να εκτελεσθεί από τον υπολογιστή.
Μια βιβλιοθήκη (library) είναι μια συλλογή από προμεταγλωττισμένα αντικείμενα αρχεία (object code) τα οποία παρέχουν κάποιες λειτουργίες (συναρτήσεις) που καλούνται επανειλημμένα από πολλά προγράμματα υπολογιστών.
Το Πρώτο Πρόγραμμα σε Pascal
Στη σύντομη ιστορία του προγραμματισμού των υπολογιστών έχει δημιουργηθεί μια παράδοση που λέει ότι το πρώτο πρόγραμμα που γράφουμε σε μια καινούργια γλώσσα που μαθαίνουμε είναι πάντα το "Hello, world". Έτσι, δεν έχουμε παρά να αντιγράψουμε τον παρακάτω κώδικα σ’ έναν κειμενογράφο (text editor), να τον αποθηκεύσουμε ως αρχείο με όνομα για παράδειγμα prog01.pas, να τον μεταγλωττίσουμε (compile) και να τον εκτελέσουμε (run) :
program Hello;
begin (* Κυρίως πρόγραμμα – αρχή *)
writeln('Hello, world.')
end. (* Κυρίως πρόγραμμα – τέλος *)
Η έξοδος που θα δημιουργηθεί θα είναι ως εξής :
Hello, world.
Η Δομή ενός Προγράμματος σε Pascal
Η βασική δομή (structure) ενός προγράμματος σε Pascal έχει ως εξής :
PROGRAM ProgramName (FileList);
CONST (* Δηλώσεις Σταθερών – Constant declarations *)
TYPE (* Δηλώσεις Τύπων Δεδομένων – Type declarations *)
VAR (* Δηλώσεις Μεταβλητών – Variable declarations *)
(* Ορισμοί Υποπρογραμμάτων – Subprogram definitions *)
BEGIN (* Εκτελέσιμες Εντολές *)
END.
Τα στοιχεία του προγράμματος πρέπει να είναι στη σωστή σειρά, αν και μερικά μπορεί να παραληφθούν αν δεν χρειάζονται. Ακολουθεί ένα πρόγραμμα που δεν κάνει τίποτα, αλλά έχει όλα τα απαραίτητα στοιχεία :
program DoNothing;
begin
end.
Τα σχόλια (comments) στην Pascal αρχίζουν με τα σύμβολα (* και τελειώνουν με τα σύμβολα *). Δεν μπορούμε να εμφωλιάσουμε σχόλια μέσα σ’ άλλα σχόλια. Για παράδειγμα, ο παρακάτω συνδυασμός (* (* *) *) θα εμφανίσει λάθος (error) επειδή ο compiler ταιριάζει (αντιστοιχεί) το (* με το πρώτο *) και αγνοεί ο,τιδήποτε βρίσκεται ανάμεσά τους. Έτσι, το δεύτερο *) θα μείνει μόνο του χωρίς το αντίστοιχό του (*. Στην Turbo Pascal, μπορούμε να χρησιμοποιήσουμε και το { Σχόλιο } αντί για το (* Σχόλιο *). Το σύμβολο { σημαίνει την αρχή ενός σχολίου και το σύμβολο } σημαίνει το τέλος ενός σχολίου.
Ο σχολιασμός έχει δύο βασικούς στόχους : πρώτα απ’ όλα κάνει τον κώδικά μας πιο εύκολα κατανοητό και από έναν τρίτο που βλέπει το πρόγραμμα για πρώτη φορά αλλά και για εμάς τους ίδιους που μετά από κάποιο χρονικό διάστημα είναι φυσικό να έχουμε ξεχάσει τις μεταβλητές που έχουμε χρησιμοποιήσει και για ποιο σκοπό τις έχουμε χρησιμοποιήσει. Μια άλλη χρήση των σχολίων είναι για να απομονώσουμε προσωρινά ένα κομμάτι του προγράμματος και να μπορέσουμε να εντοπίσουμε έτσι κάποια λάθη που εμφανίζονται κατά την εκτέλεσή του.
Όταν δεν γνωρίζουμε την αιτία ενός λάθους στον κώδικά μας, μπορούμε να τοποθετήσουμε ένα ύποπτο κομμάτι κώδικα μέσα στα σύμβολα των σχολίων και έτσι αυτό δεν θα εκτελεσθεί όταν τρέξει το πρόγραμμα. Μπορούμε να χρησιμοποιήσουμε σχόλια μέσα σ’ άλλα σχόλια χωρίς να συμβεί κάποιο λάθος, ως εξής :
{ (* Σχόλιο *) }
Τα Αναγνωριστικά (Identifiers)
Τα αναγνωριστικά (identifiers) είναι ονόματα με τα οποία μπορούμε να αναφερόμαστε σε αποθηκευμένες τιμές, όπως είναι οι μεταβλητές (variables) και οι σταθερές (constants). Επίσης, το κάθε πρόγραμμα πρέπει να αναγνωρίζεται και το ίδιο, δηλ. να έχει ένα όνομα, άρα ένα identifier. Για τα αναγνωριστικά ισχύουν οι εξής κανόνες :
Πρέπει να ξεκινούν μ’ ένα γράμμα του αγγλικού αλφαβήτου.
Μετά μπορούμε να χρησιμοποιήσουμε αλφαριθμητικούς χαρακτήρες, δηλ. αλφαβητικούς χαρακτήρες και ψηφία, καθώς και το σύμβολο _ (underscore).
Δεν πρέπει να περιέχουν μερικούς ειδικούς χαρακτήρες (σύμβολα).
Παραδείγματα ειδικών χαρακτήρων : ~ ! @ # $ % ^ & * ( ) _ + ` - = { } [ ] : " ; ' < > ? , . / | \ Η Pascal δεν ξεχωρίζει τα πεζά από τα κεφαλαία γράμματα (not case sensitive). Αυτό σημαίνει ότι τα ονόματα MyProgram, MYPROGRAM και mYpRoGrAm είναι ισοδύναμα.
Οι Σταθερές (Constants)
Οι σταθερές (constants) είναι κι αυτές αναγνωριστικά (identifiers) και μπορούν να έχουν μία μόνο τιμή που τους αποδίδεται στην αρχή του προγράμματος. Η τιμή που είναι αποθηκευμένη σε μια σταθερή δεν μπορεί να αλλάξει. Οι σταθερές ορίζονται στο constant section, ως εξής :
const
Identifier1 = value;
Identifier2 = value;
Identifier3 = value;
Ακολουθεί ένα παράδειγμα :
const
Name = 'Peter the Great';
FirstLetter = 'p';
Year = 2005;
pi = 3.1415926535897932;
UsingNetscapeNavigator = TRUE;
Το παράδειγμα αυτό δείχνει τους κύριους τύπους δεδομένων (data types) που χρησιμοποιούνται στην Pascal : συμβολοσειρές (strings), χαρακτήρες (characters), ακέραιοι (integers), πραγματικοί (reals) και λογικές τιμές (Booleans). Οι χαρακτήρες εμπεριέχονται σε απλά εισαγωγικά ή αποστρόφους ('). Οι σταθερές είναι χρήσιμες όταν σκοπεύουμε να χρησιμοποιήσουμε ένα όνομα ή έναν αριθμό στο πρόγραμμά μας που δεν αλλάζει ποτέ ή αλλάζει πολύ σπάνια.
Για παράδειγμα, αν σκοπεύουμε να χρησιμοποιήσουμε τον γνωστό αριθμό π=3,1415926 της γεωμετρίας, θα μπορούσαμε να τον δηλώσουμε ως μια σταθερά. Επίσης, το ποσοστό του ΦΠΑ σ’ ένα πρόγραμμα τιμολόγησης θα είναι συνήθως σταθερό, έστω 18%. Το δηλώνουμε ως μια σταθερά και αν ποτέ αλλάξει, όπως άλλαξε πρόσφατα και έγινε 19%, τότε κάνουμε την αλλαγή μία μόνο φορά στη δήλωση και όχι παντού μέσα στο πρόγραμμα όπου υπεισέρχεται σε υπολογισμούς. Επίσης, ως σταθερές μπορούμε να δηλώσουμε και ονόματα, όπως την επωνυμία μιας επιχείρησης, η οποία είτε δεν αλλάζει ποτέ ή αλλάζει πολύ σπάνια.
Ακολουθεί ένα παράδειγμα :
const
pi = 3.1415926535897932;
FPA = 0.19;
Company = ‘Import-Export SA‘;
Με τον τρόπο αυτό, το υπόλοιπο μέρος του προγράμματος δεν θα αλλάζει καθόλου επειδή θα αναφέρεται στην σταθερά. Εμείς απλά θα αλλάζουμε την τιμή της σταθεράς στην αρχή του προγράμματος.
Οι Μεταβλητές και οι Τύποι Δεδομένων
Οι μεταβλητές (variables) είναι παρόμοιες με τις σταθερές (constants), αλλά οι τιμές τους μπορούν να αλλάξουν όσο εκτελείται το πρόγραμμα. Στην Pascal θα πρέπει να δηλώσουμε (declare) στο τμήμα var τις μεταβλητές πριν μπορέσουμε να τις χρησιμοποιήσουμε, ως εξής :
var
IdentifierList1 : DataType1;
IdentifierList2 : DataType2;
IdentifierList3 : DataType3;
Η IdentifierList είναι μια σειρά από αναγνωριστικά (identifiers), χωρισμένα με κόμματα. Όλα τα αναγνωριστικά της ίδιας λίστας δηλώνονται ότι ανήκουν στον ίδιο τύπο δεδομένων (data type).
Οι βασικοί τύποι δεδομένων της Pascal είναι οι εξής :
integer
real
char
Boolean
Περισσότερα στοιχεία για τους τύπους δεδομένων της Pascal :
Ο ακέραιος τύπος δεδομένων (integer) περιέχει ακέραιες τιμές από –32768 έως και 32767.
Ο πραγματικός τύπος δεδομένων (real) περιέχει θετικές τιμές από 3.4 x 10-38 έως και 3.4 x 1038.
Οι πραγματικές τιμές μπορούν να γραφούν είτε με τον συμβολισμό της σταθερής υποδιαστολής (fixed-point notation) είτε με τον επιστημονικό συμβολισμό (scientific notation), με τον χαρακτήρα Ε να διαχωρίζει τη βάση (mantissa) από τον εκθέτη (exponent). Έτσι, το 452.13 είναι το ίδιο με το 4.5213e2.
Ο τύπος δεδομένων χαρακτήρα (char) περιέχει χαρακτήρες (characters), τους οποίους θα πρέπει να περικλείσουμε με μονές αποστρόφους, ως εξής : 'a' 'B' '+'.
Ο τύπος δεδομένων Boolean έχει μόνο δύο δυνατές τιμές : TRUE και FALSE.
Ακολουθεί ένα παράδειγμα δήλωσης μεταβλητών :
var
age, year, bathmos : integer;
circumference : real;
LetterGrade : char;
Epityxia : Boolean;
Εφόσον έχουμε δηλώσει μια μεταβλητή, μπορούμε να αποθηκεύσουμε κάποια τιμή σ’ αυτήν. Η διαδικασία απόδοσης τιμής σε μια μεταβλητή αποκαλείται εκχώρηση (assignment). Για να εκχωρήσουμε μια τιμή σε μια μεταβλητή, χρησιμοποιούμε την εξής σύνταξη :
όνομα_μεταβλητής := έκφραση;
Αντίθετα μ’ άλλες γλώσσες προγραμματισμού, όπου ο τελεστής εκχώρησης είναι απλά το σύμβολο =, η Pascal χρησιμοποιεί τα σύμβολα :=. Ένας βασικός λόγος για τη χρήση και του συμβόλου : στην εκχώρηση των τιμών είναι για να μην μπερδεύουν οι αρχάριοι χρήστες της γλώσσας την εκχώρηση τιμής με τη σύγκριση δύο τιμών.
Επίσης, ο συμβολισμός := θυμίζει το σχήμα του συμβόλου ß (βελάκι) και κάνει έτσι πιο κατανοητή την διαδικασία απόδοσης (εκχώρησης) μιας τιμής από τις πράξεις που γίνονται στο δεξί μέρος (έκφραση) και την καταχώρηση του αποτελέσματος στην μεταβλητή που βρίσκεται στο αριστερό μέρος.
Η έκφραση (expression) μπορεί να είναι μία μόνο τιμή :
apotelesma := 385.385837;
ή μπορεί να είναι μια πολύπλοκη αριθμητική παράσταση ;
apotelesma := 37573.5 * 37593 + 385.8 / 367.1;
Οι αριθμητικοί τελεστές της Pascal είναι οι εξής :
Τελεστής |
Πράξη |
Τελεστέοι |
Αποτέλεσμα |
+ |
Πρόσθεση |
real ή integer |
real ή integer |
- |
Αφαίρεση |
real ή integer |
real ή integer |
* |
Πολλαπλασιασμός |
real ή integer |
real ή integer |
/ |
Πραγματική διαίρεση |
real ή integer |
real |
div |
Πηλίκο ακέραιης διαίρεσης |
integer |
integer |
mod |
Υπόλοιπο ακέραιης διαίρεσης |
integer |
integer |
Οι τελεστές div και mod εργάζονται μόνο με ακέραιες τιμές. Ο τελεστής / εργάζεται και με ακέραιες και με πραγματικές τιμές αλλά έχει πάντα ως αποτέλεσμα μια πραγματική τιμή. Οι υπόλοιποι τελεστές εργάζονται και με ακέραιες και με πραγματικές τιμές. Για τους τελεστές που δέχονται και ακέραιες και πραγματικές τιμές, το αποτέλεσμα θα είναι ακέραιος αριθμός μόνο αν όλοι οι τελεστέοι είναι ακέραιοι, ενώ θα είναι πραγματικός αριθμός αν έστω και ένας από τους τελεστέους είναι πραγματικός.
Έτσι, το αποτέλεσμα της παρακάτω πράξης
3857 + 68348 * 38 div 56834
θα είναι ακέραιος αριθμός (integer), ενώ το αποτέλεσμα της παρακάτω πράξης
38573 div 34739 mod 372 + 35730 – 38834 + 1.1
θα είναι πραγματικός αριθμός, επειδή ο 1.1 είναι πραγματικός.
Η κάθε μεταβλητή μπορεί να πάρει μόνο τιμές του ίδιου τύπου δεδομένων μ’ αυτήν. Αυτό σημαίνει ότι δεν μπορούμε να εκχωρήσουμε μια πραγματική τιμή σε μια ακέραια μεταβλητή. Όμως, ορισμένοι τύποι δεδομένων είναι συμβατοί μ’ άλλους και στις περιπτώσεις αυτές μπορούμε να εκχωρήσουμε μια τιμή ενός κατώτερου τύπου δεδομένων σε μια μεταβλητή ενός ανώτερου τύπου δεδομένων.
Αυτό συμβαίνει συνήθως όταν εκχωρούμε ακέραιες τιμές σε πραγματικές μεταβλητές. Για παράδειγμα, αν έχουμε την παρακάτω δήλωση μεταβλητών :
var
some_int : integer;
some_real : real;
Τότε, όταν εκτελεσθούν οι παρακάτω εντολές :
some_int := 375;
some_real := some_int;
η μεταβλητή some_real θα έχει την τιμή 375.0 ή 3.75e2.
Στην Pascal μπορούμε να χρησιμοποιήσουμε το σύμβολο – για να δηλώσουμε έναν αρνητικό αριθμό και παρόμοια μπορούμε να χρησιμοποιήσουμε το σύμβολο + για να δηλώσουμε έναν θετικό αριθμό.
Δεν είναι σωστό να χρησιμοποιούμε δύο τελεστές δίπλα-δίπλα, όπως εδώ :
some_real := 37.5 * –2;
Η Pascal θα μπερδευτεί γιατί δεν θα γνωρίζει αν θα πρέπει να κάνει πολλαπλασιασμό ή αφαίρεση. Για να αποφεύγουμε κάποιες τέτοιες αμφιβολίες, πρέπει να χρησιμοποιούμε παρενθέσεις, ως εξής :
some_real := 37.5 * (-2);
Ο υπολογιστής χρησιμοποιεί την εξής σειρά προτεραιότητας στις αριθμητικές πράξεις :
* / div mod + –
Οι υπολογισμοί σε μια αριθμητική έκφραση γίνονται σύμφωνα με τους εξής κανόνες προτεραιότητας :
1. Πρώτα υπολογίζονται όλες οι εκφράσεις που βρίσκονται μέσα σε παρενθέσεις, ξεκινώντας από την πιο εσωτερική παρένθεση και συνεχίζοντας προς την πιο εξωτερική.
2. Μετά γίνονται όλοι οι πολλαπλασιασμοί και οι διαιρέσεις, με σειρά από αριστερά προς τα δεξιά.
3. Μετά γίνονται όλες οι προσθέσεις και οι αφαιρέσεις, με σειρά από αριστερά προς τα δεξιά.
Έτσι, για παράδειγμα, η τιμή της έκφρασης 3.5 * (2 + 3) θα είναι ίση με 17.5. Δηλαδή γίνεται πρώτα η πράξη της πρόσθεσης μέσα στην παρένθεση και μετά ο πολλαπλασιασμός.
Παραδείγματα Προγραμμάτων σε Pascal
Program prostesi; { όνομα ή επικεφαλίδα ή τίτλος του προγράμματος }
(* αυτό το πρόγραμμα προσθέτει δύο αριθμούς *)
Uses
Crt; { δήλωση της μονάδας Crt, που περιέχει συναρτήσεις οθόνης }
Var { τμήμα δηλώσεων του προγράμματος }
a, b, c : Real; { δήλωση τριών αριθμητικών μεταβλητών }
Begin { αρχή του κυρίου προγράμματος, δηλ. των εντολών }
Read(a, b); { διάβασμα τιμών για δύο μεταβλητές }
c := a+b; { υπολογισμός του αθροίσματος σε μια τρίτη μεταβλητή }
Write(c) { εμφάνιση της τιμής της μεταβλητής στην οθόνη }
End. { τέλος του προγράμματος }
(* ο χαρακτήρας ; χρησιμοποιείται για να δηλώσει το τέλος μιας εντολής και έχει λίγες μόνο εξαιρέσεις και το σύμβολο := χρησιμοποιείται για να καταχωρούμε τιμές σε μεταβλητές *)
Program fahr_cel;
(* πρόγραμμα μετατροπής θερμοκρασίας Φαρενάιτ σε Κελσίου *)
(* ο τύπος μετατροπής είναι ο εξής : CEL = ((FAHR – 32) * 5) / 9 *)
Uses
Crt;
Const
factor = 32.0; { δήλωση μιας σταθεράς }
Var
bath_fahr, bath_cel : Real;
{ bath_fahr είναι οι βαθμοί Φαρενάιτ και bath_cel είναι οι βαθμοί Κελσίου }
Begin
Writeln('Μετατροπή θερμοκρασίας από βαθμούς Φαρενάιτ ');
Writeln('σε βαθμούς Κελσίου');
Writeln; { αφήνει μια κενή γραμμή στην οθόνη }
Write('Δώσε τη θερμοκρασία σε βαθμούς Φαρενάιτ : )';
Readln(bath_fahr); { διάβασμα της θερμοκρασίας σε Φαρενάιτ }
{ υπολογισμός της θερμοκρασίας σε βαθμούς Κελσίου }
bath_cel := ((bath_fahr-factor)*5.0)/9.0;
Writeln('Αντιστοιχεί σε ', bath_cel, 'βαθμούς Κελσίου');
Writeln; { αφήνει μια κενή γραμμή στην οθόνη }
End.
Program misthos;
(* αυτό το πρόγραμμα κάνει υπολογισμό μισθοδοσίας *)
Uses
Crt;
Var
HM, ME, MA, KP, KA : Real;
{ ΗΜ είναι το ημερομίσθιο, ΜΕ είναι οι μέρες εργασίας, ΜΑ είναι οι μικτές αποδοχές, ΚΡ είναι οι κρατήσεις και ΚΑ είναι οι καθαρές αποδοχές }
Begin
Read(HM, ME);
MA := ME*HM;
KP := 0.20*MA;
KA := MA-KP;
Write(MA, KP, KA)
End.
H Εντολή If
Οι εντολές για τη λήψη αποφάσεων επιτρέπουν στο πρόγραμμα να εκτελεί διαφορετικές ενέργειες βασιζόμενο σε κάποιους λογικούς ελέγχους. Εδώ θα δούμε τις εντολές If και Case. Η εντολή If ... Then αποτελείται από τη δεσμευμένη λέξη If που ακολουθείται από μια συνθήκη και μετά από τη δεσμευμένη λέξη Then. Μετά το Then ακολουθεί μία εντολή ή ένα σύνολο εντολών. Η εντολή If ... Then ελέγχει τη συνθήκη και αν αυτή είναι αληθής (true) τότε εκτελούνται οι εντολές που βρίσκονται μετά το Then.
Η σύνταξη της εντολής είναι ως εξής :
If συνθήκη Then εντολή1
Η εντολή1 εκτελείται αν η συνθήκη είναι αληθής (true) και αγνοείται σε περίπτωση που η συνθήκη είναι ψευδής (false). Όταν μετά το Then ακολουθούν περισσότερες από μία εντολές, τότε αυτές πρέπει να εσωκλείνονται σε Begin και End για να σχηματιστεί μια σύνθετη εντολή.
Η Εντολή Else
Σε μια εντολή If μπορεί να υπάρχει προαιρετικά και η πρόταση Else, ακολουθούμενη από μία ή περισσότερες εντολές που εκτελούνται αν η συνθήκη του If είναι ψευδής. Η πρόταση Else επιτρέπει σε μια πρόταση If να πάρει δύο διαφορετικές αποφάσεις. Ανάλογα με τους ελέγχους του προγράμματος επιτρέπεται το φώλιασμα και ο συνδυασμός των εντολών If .. Then .. Else. Κάθε πρόταση Else συνδέεται με την αμέσως προηγούμενή της If.
Ακολουθεί ένα παράδειγμα :
...
If (my_age >= 18) then
Writeln(' ... ')
Else
Writeln(' ... ')
...
Στο παραπάνω παράδειγμα, αν η μεταβλητή my_age είναι μεγαλύτερη ή ίση από 18, θα εκτελεστεί η πρώτη εντολή Writeln(), αλλιώς, δηλ. αν η μεταβλητή my_age είναι μικρότερη από 18, θα εκτελεστεί η δεύτερη εντολή Writeln(), που βρίσκεται μετά την πρόταση Else.
Η Εντολή Case
Η εντολή Case επιλέγει μία πράξη ανάμεσα από πολλές με βάση το αποτέλεσμα ενός ελέγχου. Η προς έλεγχο έκφραση καλείται «επιλογέας» και κάθε επιλογή καλείται «σταθερά» της Case. Αν ο επιλογέας δεν ταιριάζει με καμία από τις σταθερές της Case, θα εκτελεστεί η δήλωση που ορίζεται με τη λέξη Else. Κάθε εντολή Case πρέπει να τερματίζεται με μια εντολή End.
Αν η έκφραση του επιλογέα είναι αριθμός, θα πρέπει να παίρνει τιμές μέσα από το πεδίο τιμών -32768 έως +32767. Έτσι, δεν μπορούν να χρησιμοποιηθούν σαν επιλογείς τα αλφαριθμητικά και οι πραγματικοί αριθμοί. Υπάρχει όμως μια ποικιλία επιλογών : Οι τύποι Char, Boolean και Set.
Η σύνταξη της εντολής Case είναι ως εξής :
Case επιλογέας of
σταθερά1 : εντολή1;
σταθερά2 : εντολή2;
...
...
...
σταθεράΝ : εντολήΝ;
Else εντολή ;
End;
Οι σταθερές της εντολής Case μπορεί να είναι απλές σταθερές, μια ομάδα ή ένα τμήμα σταθερών. Ακολουθεί ένα παράδειγμα :
...
Case val_num of
1, 3, 5, 7, 9 : Writeln(' ... ');
2, 4, 6, 8 : Writeln(' ... ');
End;
...
Στο παραπάνω παράδειγμα, αν η μεταβλητή val_num πάρει μια τιμή από τις 1, 3, 5, 7 ή 9, θα εκτελεστεί η πρώτη εντολή, ενώ αν πάρει μια τιμή από τις 2, 4, 6 ή 8, θα εκτελεστεί η δεύτερη εντολή. Οι εντολές για εκτέλεση μπορεί να είναι απλές εντολές ή ένα σύνολο εντολών (σύνθετη εντολή).
Οι Απαριθμητοί Τύποι Δεδομένων
Εκτός από τους προκαθορισμένους τύπους δεδομένων της Pascal, μπορούμε να δημιουργήσουμε και τους δικούς μας τύπους δεδομένων. Ο σκοπός αυτής της δυνατότητας είναι η δημιουργία κατανοητών προγραμμάτων, τόσο για τους προγραμματιστές, όσο και για άλλους, που ίσως ασχοληθούν μελλοντικά με τα προγράμματα αυτά. Ένα παράδειγμα τύπων δεδομένων της Pascal είναι οι : Boolean, Char, Integer και LongInt. Οι τύποι που ορίζονται από τον χρήστη μπορεί να είναι απαριθμητοί με οποιοδήποτε πεδίο τιμών.
Οι απαριθμητοί τύποι δεδομένων αποτελούνται από μια διατεταγμένη σειρά μοναδικών προσδιοριστικών. Το τμήμα ορισμού τύπων ξεκινάει με τη δεσμευμένη λέξη Type, την οποία ακολουθούν ένα ή περισσότερα προσδιοριστικά τύπων. Κάθε ορισμός αποτελείται από ένα όνομα, ένα σύμβολο ισότητας και την περιγραφή του τύπου που καθορίζεται. Η συντακτική μορφή ενός τέτοιου τύπου είναι η εξής :
Type Όνομα = (προσδιοριστικό1[, προσδιοριστικό2...])
Η Pascal δίνει αύξοντες αριθμούς στα προσδιοριστικά του απαριθμητού τύπου, αρχίζοντας από το μηδέν. Με τον τρόπο αυτό επιτυγχάνεται μια εσωτερική αναπαράσταση των προσδιοριστικών.
Ακολουθεί ένα παράδειγμα ορισμού απαριθμητού τύπου :
Type
japanese_cars = (honda, isuzu, nissan, toyota);
Var
rental_car : japanese_cars;
Begin
rental_car := nissan;
Έτσι το προσδιοριστικό nissan με την τιμή 2, εκχωρείται στην μεταβλητή rental_car.
Ακολουθεί η παρουσίαση των συναρτήσεων και των διαδικασιών που χρησιμοποιεί η Pascal για τον χειρισμό των απαριθμητών τύπων.
Η Συνάρτηση Succ()
Επιστρέφει σαν τιμή το αμέσως επόμενο στοιχείο κάποιου τακτικού τύπου. Ακολουθούν μερικά παραδείγματα χρήσης της :
ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΗΣ |
ΤΑΚΤΙΚΟΣ ΤΥΠΟΣ |
ΑΠΟΤΕΛΕΣΜΑ |
succ(second) |
place |
third |
succ(isuzu) |
japanese_cars |
nissan |
succ(15) |
Integer |
16 |
succ('a') |
Char |
'b' |
succ(False) |
Boolean |
True |
Επιστρέφει σαν τιμή το προηγούμενο στοιχείο κάποιου τακτικού τύπου. Ακολουθούν μερικά παραδείγματα χρήσης της :
ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΗΣ |
ΤΑΚΤΙΚΟΣ ΤΥΠΟΣ |
ΑΠΟΤΕΛΕΣΜΑ |
pred(second) |
place |
first |
pred(isuzu) |
japanese_cars |
honda |
pred(15) |
Integer |
14 |
pred('b') |
Char |
'a' |
pred(True) |
Boolean |
False |
Η Συνάρτηση Ord()
Επιστρέφει σαν τιμή την τακτική τιμή κάποιου απαριθμητού τύπου, όπου οι τακτικές τιμές αρχίζουν από το 0. Ακολουθούν μερικά παραδείγματα χρήσης της :
ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΗΣ |
ΤΑΚΤΙΚΟΣ ΤΥΠΟΣ |
ΑΠΟΤΕΛΕΣΜΑ |
ord(first) |
place |
1 |
ord(toyota) |
japanese_cars |
3 |
ord('a') |
Char |
97 |
ord(False) |
Boolean |
0 |
Βλέπουμε ότι όσον αφορά τις μεταβλητές τύπου char, επιστρέφει τον ASCII κώδικα της μεταβλητής και μπορεί γενικά να χρησιμοποιηθεί μ’ οποιονδήποτε τύπο δεδομένων.
Επιστρέφει μια τιμή τύπου Boolean, που είναι True όταν η τιμή του απαριθμητού τύπου είναι περιττή και False όταν η τιμή του απαριθμητού τύπου είναι άρτια. Ακολουθούν μερικά παραδείγματα χρήσης της :
ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΗΣ |
ΤΑΚΤΙΚΟΣ ΤΥΠΟΣ |
ΑΠΟΤΕΛΕΣΜΑ |
odd(ord(first)) |
place |
True |
odd(ord(toyota)) |
japanese_cars |
True |
odd(ord('b')) |
Char |
False |
odd(ord(False)) |
Boolean |
False |
Η Συνάρτηση Chr()
Δέχεται σαν είσοδο παραμέτρους τύπου Integer ή Byte και επιστρέφει σαν τιμή τον αντίστοιχο ASCII χαρακτήρα. Ακολουθούν μερικά παραδείγματα χρήσης της
ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΗΣ |
ΑΠΟΤΕΛΕΣΜΑ |
chr(65) |
A |
chr(79) |
O |
chr(ord(J)) |
J |
chr(ord(W)) |
W |
Η Διαδικασία Inc
Αυξάνει μια μεταβλητή τόσες φόρες, όσες δηλώνει το νούμερο του στοιχείου. Για παράδειγμα, η εντολή inc(status, 2); αυξάνει την μεταβλητή status κατά 2, ενώ αν δεν δηλωθεί κανένας αριθμός, τότε η μεταβλητή αυξάνεται κατά ένα : inc(status);.
Η Διαδικασία Dec
Ελαττώνει μια μεταβλητή τόσες φόρες, όσες δηλώνει το νούμερο του στοιχείου. Για παράδειγμα, η εντολή dec(status, 2); ελαττώνει την μεταβλητή status κατά 2, ενώ αν δεν δηλωθεί κανένας αριθμός, τότε η μεταβλητή ελαττώνεται κατά ένα : dec(status);.
Συχνά κρίνεται σκόπιμο να περιοριστεί η χρήση μιας μεταβλητής μόνο σ’ ένα διάστημα τιμών. Η Pascal διαθέτει τον τύπο υποδιαστήματος για τον σκοπό αυτό. Το υποδιάστημα πρέπει να είναι ένα υποσύνολο ενός προκαθορισμένου ή ενός απαριθμητού τύπου, ο οποίος καλείται πατρικός (host). Το διάστημα τιμών πρέπει να είναι συνεχές. Για να οριστεί ένα υποδιάστημα, απλά δηλώνουμε το όνομα του υποδιαστήματος, η κατώτατη και η ανώτατη τιμή του υποδιαστήματος και οι δύο αυτές τιμές διαχωρίζονται με δύο τελείες, ως εξής :
Όνομα_Υποδιαστήματος = Κατώτατη_Τιμή..Ανώτατη_Τιμή
Οι δύο τιμές πρέπει να είναι σταθερές του ίδιου τύπου και η κατώτατη τιμή να είναι διατεταγμένη πριν από την ανώτατη τιμή, δηλ. :
Ord(Κατώτατη_Τιμή) <= Ord(Ανώτατη_Τιμή)
Η Pascal ελέγχει αυτόματα τα όρια των υποδιαστημάτων σε προτάσεις άμεσης εκχώρησης.
Με τα ακέραια υποδιαστήματα ορίζουμε ένα όριο έγκυρων ακέραιων τιμών, ως εξής :
Type
screen_columns = 1..80;
days = 1..31;
months = 1..12;
seconds = 0..59;
minutes = 0..59;
hours = 0..23;
Const
max_col = 80;
max_row = 25;
max_days_per_month = 31;
months_per_year = 12;
Type
screen_columns = 1..max_col;
screen_rows = 1..max_row;
days = 1..max_days_per_month;
months = 1..months_per_year;
Η Pascal επιτρέπει ακόμη και εκφράσεις με τους ορισμούς υποδιαστημάτων :
Const
sec_per_minute = 60;
minute_per_hour = 60;
hour_per_day = 24;
Type
seconds = 0..sec_per_minute-1;
minutes = 0..minute_per_hour-1;
hours = 0..hour_per_day-1;
Με τα υποδιαστήματα χαρακτήρων ορίζουμε ένα όριο αποδεκτών τιμών τύπου char, ως εξής :
Type
up_case_char = 'A'..'Z';
lo_case_char = 'a'..'z';
digit_char = '0'..'9';
Με τα απαριθμητά υποδιαστήματα ορίζουμε ένα όριο αποδεκτών απαριθμητών τιμών, ως εξής :
Type
vehicles=(volkswagen, honda, toyota, corvette, porsche, ferrari, bronco);
economy_cars = volkswagen..toyota;
sports_cars = corvette..ferrari;
Τα σύνολα είναι τύποι δεδομένων που ορίζονται από τον χρήστη και οι οποίοι έχουν κάποιο βαθμό δόμησης. Όπως και στα μαθηματικά, έτσι και στην Pascal, ένα σύνολο (set) είναι μια διατεταγμένη συλλογή στοιχείων. Ένα σύνολο αποτελείται από μια πεπερασμένη συλλογή (μοναδικών) στοιχείων τα οποία βρίσκονται στον ίδιο προκαθορισμένο τύπο, ο οποίος καλείται βασικός. Η γενική μορφή δήλωσης ενός συνόλου είναι η εξής :
Type 'Ονομα_Συνόλου = Set of Τακτικός_Τύπος
Ο Τακτικός_Τύπος είναι ένα διατεταγμένο σύνολο τιμών, τα στοιχεία του πρέπει να είναι όλα του ίδιου τύπου και πρέπει να αποτελεί ένα απλό στοιχείο ή ένα υποδιάστημα. Ο Τακτικός_Τύπος δεν μπορεί να έχει πάνω από 256 πιθανές τιμές.
Για παράδειγμα :
Const
vowels = ['A', 'E', 'I', 'O', 'U'];
upper_case = Set of 'A'..'Z' = ['A'..'Z'];
Αφού οριστεί κάποιο σύνολο, ο τελεστής Ιn χρησιμεύει για να εξετάσει την παρουσία ή την απουσία κάποιου συγκεκριμένου στοιχείου από το σύνολο, ως εξής
If ch In upper_case Then ...
If ch In vowels Then ...
Στα παραπάνω παραδείγματα, το In επιστρέφει την τιμή true αν το ch είναι στοιχείο του αντίστοιχου συνόλου και false αν δεν είναι.
Τα σύνολα μπορούν να οριστούν με πολλούς τρόπους :
Προκαθορισμένοι τακτικοί τύποι :
Type
boolean_set = Set of Boolean;
char_set = Set of Char;
byte_set = Set of Byte;
Υποδιαστήματα προκαθορισμένων τύπων :
Type
bits = 1..7;
byte_bitrs = Set of bits;
up_case = Set of 'A'..'Z';
lo_case = Set of 'a'..'z';
Απαριθμητοί τύποι :
Type
transportation = (bicycle, motorcycle, car, truck, bus);
four_wheels = car..bus;
trans_set = Set of transportation;
four_wheel_set = Set of four_wheels;
Μεταβλητές :
Var
fast_trans : four_wheels;
lower_letters : lo_case;
num1, num2 : byte_bits;
Σταθερές :
Const
vowels : Set of Char = ['A', 'E', 'I', 'O', 'U'];
up_chars : Set of Char = ['A'..'Z'];
lo_chars : Set of Char = ['a'..'z'];
Εκχώρηση Στοιχείων Συνόλων σε Μεταβλητές
Για την εκχώρηση στοιχείων συνόλων σε μεταβλητές χρησιμοποιούνται οι αγκύλες, ως εξής :
Μεταβλητή_Συνόλου := [Στοιχείο_Συνόλου]
Το κενό σύνολο είναι το [ ] και με τη βοήθειά του μπορούμε να μηδενίσουμε μεταβλητές συνόλων. Ένα σύνολο μπορεί να αποτελείται από μια σειρά στοιχείων, ένα υποδιάστημα ή από τον συνδυασμό και των δύο, ως εξής :
set1 := [1, 3, 5, 7, 9]
set2 := [0..7];
set3 := [0..7, 14, 15, 16];
char_list := ['A'..'Z', 'a'..'z', '0'..'9'];
Οι τελεστές συνόλων προσφέρουν τρόπους για την δημιουργία νέων συνόλων με στοιχεία από ήδη υπάρχοντα σύνολα. Οι τελεστές συνόλων που υποστηρίζει η Pascal είναι οι εξής :
Οι σχεσιακοί τελεστές έχουν ως σκοπό την εύρεση της σχέσης δύο ή περισσοτέρων συνόλων. Βασισμένος στις πιθανές καταστάσεις κάποιας σχέσης, ο τελεστής επιστρέφει την τιμή True ή False.
Ο παρακάτω πίνακας παρουσιάζει τους σχεσιακούς τελεστές που χρησιμοποιούνται στα σύνολα :
ΤΕΛΕΣΤΗΣ |
ΣΥΝΤΑΞΗ |
ΕΠΙΣΤΡΕΦΕΙ TRUE ΑΝ |
= |
Σύνολο Α = Σύνολο Β |
Τα Α και Β είναι ταυτόσημα. |
<> |
Σύνολο Α <> Σύνολο Β |
Ένα από τα σύνολα περιέχει τουλάχιστον ένα στοιχείο που δεν βρίσκεται στο άλλο. |
<= |
Σύνολο Α <= Σύνολο Β |
Κάθε στοιχείο του Α είναι και στο Β. |
< |
Σύνολο Α < Σύνολο Β |
Κάθε στοιχείο του Α είναι και στο Β και επιπλέον στο Β υπάρχει τουλάχιστον ένα στοιχείο που δεν βρίσκεται στο Α. |
>= |
Σύνολο Α >= Σύνολο Β |
Κάθε στοιχείο του Β είναι και στο Α. |
> |
Σύνολο Α > Σύνολο Β |
Κάθε στοιχείο του Β είναι και στο Α και επιπλέον στο Α υπάρχει τουλάχιστον ένα στοιχείο που δεν βρίσκεται στο Β. |
ΙΝ |
Στοιχείο στο Σύνολο Α |
Το στοιχείο υπάρχει στο σύνολο Α. |
Ο τελεστής Ιn εξετάζει την σχέση δύο ή περισσοτέρων συνόλων. Επιστρέφει ένα αποτέλεσμα τύπου Boolean, ανάλογα με το αν κάποιο στοιχείο είναι μέρος του συνόλου. Το εξεταζόμενο στοιχείο θα πρέπει να είναι του ιδίου τύπου ή συμβατού με τον βασικό τύπο του συνόλου.
Η σύνταξή του είναι η εξής :
Όνομα_Στοιχείου Ιn Όνομα_Συνόλου
Ακολουθούν παραδείγματα :
ch In vowels
'i' In consonants
operator In ['+', '-', '/', '*']
Ο τελεστής ένωσης συνόλων (+) ενώνει δύο σύνολα και το αποτέλεσμα εκχωρείται σ’ ένα τρίτο σύνολο. Αν τα δύο σύνολα είναι το ένα υποσύνολο του άλλου, το αποτέλεσμα θα είναι ένα σύνολο ίδιο με το μεγαλύτερο σύνολο.
Ακολουθούν παραδείγματα :
set1 := ['A'..'Z'];
set2 := ['a'..'z'];
set3 := set1 + set2;
set3 := ['A'..'Z', 'a'..'z']; { είναι ίδια με την προηγούμενη εντολή }
set1 := ['A'..'L'];
set2 := ['H'..'Z'];
set3 := set1 + set2;
set3 := ['A'..'Z']; { είναι ίδια με την προηγούμενη εντολή }
Στο παραπάνω παράδειγμα υπάρχουν κοινά στοιχεία στα δύο σύνολα και φυσικά αυτά τα στοιχεία θα εμφανιστούν από μία μόνο φορά στο νέο σύνολο.
set1 := ['A'..'L'];
set2 := ['F'..'J'];
set3 := set1 + set2;
set3 := ['A'..'L']; { είναι ίδια με την προηγούμενη εντολή }
Τα set1 και set3 είναι ίδια, γιατί το set2 είναι υποσύνολο του set1.
Ακολουθεί ένα παράδειγμα που μηδενίζει πρώτα έναν χαρακτήρα συνόλου και μετά μ’ έναν βρόχο for προσθέτει στο σύνολο τους χαρακτήρες A, B, C, D, F, ...
set1 := [ ] { μηδενισμός συνόλου }
for ch := 'A' to 'Z' do
set1 := set1 + [ch];
Ο τελεστής διαφοράς συνόλων (-) δημιουργεί ένα σύνολο που περιέχει όλα τα στοιχεία του πρώτου συνόλου τα οποία δεν εμφανίζονται στο δεύτερο σύνολο.
Ακολουθούν παραδείγματα :
set1 := ['A'..'Z'];
set2 := ['a'..'z'];
set3 := set1 - set2;
set3 := ['A'..'Z']; { είναι ίδια με την προηγούμενη εντολή }
set1 := ['A'..'L'];
set2 := ['H'..'Z'];
set3 := set1 - set2;
set3 := ['A'..'G']; { είναι ίδια με την προηγούμενη εντολή }
set1 := ['A'..'L'];
set2 := ['F'..'J'];
set3 := set1 - set2;
set3 := ['A'..'E', 'K', 'L']; { είναι ίδια με την προηγούμενη εντολή }
Είδαμε ότι με τον τελεστή πρόσθεσης συνόλων μπορούμε να προσθέσουμε νέα στοιχεία σ’ ένα σύνολο, ενώ με τον τελεστή διαφοράς συνόλων μπορούμε να διαχωρίσουμε τα στοιχεία ενός συνόλου.
Ακολουθούν παραδείγματα :
set1 := ['A'..'Z' ] { απόδοση αρχικής τιμής συνόλου }
for ch := 'A' to 'Z' do
set1 := set1 – [ch];
Ο τελεστής τομής συνόλων (*) χρησιμοποιείται για την απόσπαση των κοινών στοιχείων που υπάρχουν σε δύο όμοιους τύπους συνόλων.
Ακολουθούν παραδείγματα :
set1 := ['A'..'L'];
set2 := ['H'..'Z'];
set3 := set1 * set2;
set3 := ['H'..'L']; { είναι ίδια με την προηγούμενη εντολή }
Τα δύο σύνολα έχουν κοινά στοιχεία.
set1 := ['A'..'L'];
set2 := ['F'..'J'];
set3 := set1 * set2;
set3 := ['F'..'J']; { είναι ίδια με την προηγούμενη εντολή }
Το set2 είναι υποσύνολο του set1, έτσι set3 = set2.
set1 := ['A'..'L'];
set2 := ['a'..'z'];
set3 := set1 * set2;
set3 := [ ]; { είναι ίδια με την προηγούμενη εντολή }
Τα δύο σύνολα δεν έχουν κοινά στοιχεία.
Οι Διαδικασίες και οι Συναρτήσεις
Ένα υποπρόγραμμα (subprogram) ή υπορουτίνα (subroutine) είναι ένα σύνολο εντολών της Pascal που κάνει μια συγκεκριμένη λειτουργία και γράφεται με τους ίδιους κανόνες που γράφεται ένα πρόγραμμα. Τα υποπρογράμματα χωρίζονται σε δύο κατηγορίες : τις διαδικασίες (procedures) και τις συναρτήσεις (functions).
Η διαδικασία (procedure) είναι ένα υποπρόγραμμα που έχει σαν αποτέλεσμα την εκτέλεση μιας σειράς πράξεων για έναν και μοναδικό σκοπό. Η συνάρτηση είναι ένα υποπρόγραμμα ειδικά σχεδιασμένο να επιστρέφει μία και μόνο μία τιμή· συνεπώς οι συναρτήσεις καλούνται μόνο μέσα σε εκφράσεις. Διαδικασίες που ορίζονται μέσα από την Turbo Pascal, όπως οι Write, Writeln, Read και Readln καλούνται πρότυπα (standard) υποπρογράμματα. Όταν τα πρότυπα υποπρογράμματα δεν είναι κατάλληλα για τον σκοπό μας, μπορούμε να ορίσουμε νέα, μέσω μιας δήλωσης διαδικασίας ή συνάρτησης. Αφού οριστεί το νέο υποπρόγραμμα, τότε αυτό μπορεί να κληθεί απλά με το όνομά του όπως καλούνται και τα πρότυπα υποπρογράμματα.
Για παράδειγμα, το παρακάτω πρόγραμμα περιέχει μια διαδικασία που κεντράρει μια γραμμή στην οθόνη.
Program Center;
Uses crt;
Var
row : Byte;
title : String;
Procedure center_line(message : String; line : Byte);
Begin
GotoXY(40 - Length(message) div 2, line);
Writeln(message);
End;
Begin { Κύριο Πρόγραμμα }
row := 2;
title := 'Κάθε γραμμή κειμένου κεντράρεται.';
Clrscr;
center_line(title, row); { κλήση της διαδικασίας }
center_line('--------', row+1);
center_line('Borland Turbo Pascal !', row+2);
End.
Το αποτέλεσμα του προγράμματος είναι το εξής :
Κάθε γραμμή κειμένου κεντράρεται
-------
Borland Turbo Pascal !
Όπως είδαμε, μια διαδικασία εκτελείται δηλώνοντας απλά το όνομά της μαζί με οποιεσδήποτε απαιτούμενες παραμέτρους. Η παράμετρος είναι μια πληροφορία (συνήθως μια μεταβλητή), η οποία μεταφέρεται μεταξύ της διαδικασίας και του κυρίου προγράμματος.
Η διαδικασία center_line, που είδαμε προηγουμένως, απαιτεί τα εξής δεδομένα (παραμέτρους) : ένα κομμάτι κειμένου που κεντράρεται, καθώς και τη γραμμή στην οποία θέλουμε να το τυπώσουμε. Οι παράμετροι χωρίζονται με κόμματα μεταξύ τους. Η πρώτη παράμετρος είναι μια συμβολοσειρά (String), ενώ η δεύτερη παράμετρος είναι ένας αριθμός.
Ο ορισμός μιας διαδικασίας αποτελείται από τρία μέρη : Τον τίτλο, τα δεδομένα και το κύριο μέρος (σώμα) της διαδικασίας.
Ο τίτλος της διαδικασίας αποτελείται από τη δεσμευμένη λέξη Procedure που ακολουθείται από το όνομα της διαδικασίας καθώς και από τις απαιτούμενες παραμέτρους.
Τα δεδομένα που πρόκειται να χειριστούν οι εντολές της διαδικασίας, ορισμένα σαν επικεφαλίδες, σταθερές, τύποι και μεταβλητές, δηλώνονται μετά τον τίτλο αλλά πριν από την πρώτη εντολή της διαδικασίας.
Το κύριο μέρος ή «σώμα» της διαδικασίας αποτελείται από ένα σύνολο εκτελέσιμων εντολών, όπου περιγράφονται οι πράξεις που πρόκειται να γίνουν. Οι εντολές της διαδικασίας περικλείονται από τις δεσμευμένες λέξεις Begin και End ακολουθούμενες από ένα ελληνικό ερωτηματικό ;.
Η γενική σύνταξη μιας διαδικασίας έχει ως εξής :
Τίτλος διαδικασίας (Προαιρετικές παράμετροι);
{ Δηλώσεις δεδομένων }
begin
{ Εντολές προγράμματος }
end;
Ο τίτλος της διαδικασίας είναι υποχρεωτικός, ενώ τα δεδομένα και οι εντολές είναι προαιρετικά. Η Pascal γενικά απαιτεί τον προσδιορισμό κάποιας οντότητας πριν τη χρησιμοποίησή της. Για παράδειγμα, για να χρησιμοποιήσουμε μια μεταβλητή χρειάζεται να δηλώσουμε το όνομά της καθώς και τον τύπο της. Ο ίδιος κανόνας ισχύει και για τις διαδικασίες.
Υπάρχουν περιπτώσεις, όμως, όπου απαιτείται η κλήση κάποιας διαδικασίας πριν αυτή οριστεί. Αυτό μπορεί να επιτευχθεί με τον Προορισμό της διαδικασίας. Ο Προορισμός της διαδικασίας είναι παρόμοιος με τον ορισμό της, μόνο που στην πρώτη περίπτωση ο ορισμός της διαδικασίας ακολουθείται από τη δεσμευμένη λέξη Forward και αυτή από ένα ελληνικό ερωτηματικό ;.
Για παράδειγμα, για την περίπτωση του Προορισμού της διαδικασίας που είδαμε, θα είχαμε :
Procedure center_line(message : String; line : Byte);
Forward;
Ο ορισμός των τοπικών μεταβλητών γίνεται στο τμήμα δηλώσεων των δεδομένων μιας διαδικασίας. Όλες οι μεταβλητές που ορίζονται μέσα σε φωλιασμένες διαδικασίες ή συναρτήσεις λέγονται τοπικές γι' αυτή τη διαδικασία ή συνάρτηση. Οι τοπικές μεταβλητές γίνονται κατανοητές από τον μεταγλωττιστή μόνο μέσα σ’ αυτές και πουθενά αλλού μέσα στο πρόγραμμα.
Το παράδειγμα που ακολουθεί περιέχει δύο τοπικές μεταβλητές και απαιτεί από τον χρήστη να δώσει έναν αριθμό, προκειμένου να βρεθεί το παραγοντικό του. Το παραγοντικό π.χ. του 6 είναι το γινόμενο 1*2*3*4*5*6.
Program local_variables;
Var
num : Byte;
Procedure factor(value : Byte);
Var
factorial : Real;
count : Byte;
Begin
factorial := 1.0;
For count := 1 To value Do
factorial := factorial * count;
Write('Το παραγοντικό του ', value,' είναι : ' );
Writeln(factorial);
End; { Τέλος της διαδικασίας Factor }
Begin { Κύριο πρόγραμμα }
Write('Δώστε έναν αριθμό μικρότερο του 34 : ');
Readln(num);
Factor(num);
End. { Τέλος του προγράμματος }
Ένα παράδειγμα από τη λειτουργία του προγράμματος είναι το εξής :
Δώστε έναν αριθμό μικρότερο του 34 : 5
Το παραγοντικό του 5 είναι : 1.200000000Ε+02
Το σημείο ορισμού των τοπικών μεταβλητών είναι πριν από το Begin της διαδικασίας και μετά από τον τίτλο της. Σε αντίθεση με τις καθολικές (global) μεταβλητές που δηλώνονται έξω από οποιαδήποτε διαδικασία και είναι «ορατές» σ’ ολόκληρο το πρόγραμμα, οι τοπικές μεταβλητές ορίζονται μέσα σε μια διαδικασία και δεν γίνονται κατανοητές από το υπόλοιπο πρόγραμμα.
Αν αναφερθούμε σε μια τοπική μεταβλητή έξω από το όριο στο οποίο είναι αυτή κατανοητή, η Pascal θα εμφανίσει το παρακάτω μήνυμα λάθους : Error 3 : "Unknown identifier". Όταν ορισθεί μια μεταβλητή στον τίτλο μιας διαδικασίας σαν παράμετρος, τότε η μεταβλητή αυτή γίνεται τοπική. Π.χ. στο προηγούμενο παράδειγμα δημιουργήθηκε μια τοπική μεταβλητή με το όνομα value, που στο εσωτερικό της διαδικασίας συμπεριφέρεται όπως οποιαδήποτε άλλη τοπική μεταβλητή.
Οι παράμετροι στις οποίες δεν προηγείται η δεσμευμένη λέξη Var αλλά ακολουθούνται από ένα συγκεκριμένο τύπο, καλούνται παράμετροι τιμής. Όταν μια παράμετρος περνάει με τιμή, στην διαδικασία μεταβιβάζεται ένα αντίγραφο της τιμής της πραγματικής παραμέτρου. Η διαδικασία που κλήθηκε προηγουμένως δεν έχει πρόσβαση στην πραγματική μεταβλητή και έτσι δεν μπορεί να την τροποποιήσει.
Στο πρόγραμμα που ακολουθεί παρουσιάζεται το πέρασμα παραμέτρων με τιμή :
Program byvalue;
Var
global_var : Integer;
Procedure proc(local_var : Integer);
Begin
Writeln('Τοπική μεταβλητή = ', local_var);
local_var := 333;
Writeln('Τοπική μεταβλητή = ', local_var);
End;
Begin { Κύριο πρόγραμμα }
global_var := 5;
proc(global_var);
Writeln('Καθολική μεταβλητή = ', global_var);
End.
Το αποτέλεσμα του προγράμματος θα είναι :
Tοπική μεταβλητή = 5
Tοπική μεταβλητή = 333
Kαθολική μεταβλητή = 5
Βλέπουμε ότι η μεταβλητή global_var δεν επηρεάζεται από την διαδικασία και ότι δίνει την τιμή της στην local_var.
Αν θέλουμε μια διαδικασία να έχει απ' ευθείας πρόσβαση σε μια πραγματική παράμετρο, τοποθετούμε τη δεσμευμένη λέξη Var πριν από την δήλωση της τυπικής παραμέτρου. Αυτό έχει ως αποτέλεσμα η τυπική παράμετρος να χαρακτηρίζεται σαν μεταβλητή παράμετρος και η ενέργεια αυτή λέγεται Πέρασμα Παραμέτρου με Αναφορά.
Όταν χρησιμοποιείται αυτή η μέθοδος, τότε αντί για ένα αντίγραφο της τιμής της παραμέτρου μεταβιβάζεται η ίδια η διεύθυνση της πραγματικής παραμέτρου. Η διαδικασία μπορεί τότε να χρησιμοποιήσει την διεύθυνση της πραγματικής παραμέτρου για να έχει πρόσβαση στην ίδια και να τροποποιήσει έτσι την τιμή της.
Το παρακάτω πρόγραμμα παρουσιάζει την μέθοδο αυτή :
Program byref;
Var
var, var2 : Integer;
Procedure swap_vars(Var var1 : Integer; Var var2 : Integer);
Var
temp : Integer;
Begin
temp := var1;
var1 := var2;
var2 := temp;
End;
Begin
var1 := 55;
var2 := 99;
Writeln('Μεταβλητή1 = ', var1, 'Μεταβλητή2 = ', var2);
swap_vars(var1, var2);
Writeln('Μεταβλητή1 = ', var1, 'Μεταβλητή2 = ', var2);
End.
Το αποτέλεσμα του προγράμματος θα είναι το εξής :
Μεταβλητή1 = 55 Μεταβλητή2 = 99
Μεταβλητή1 = 99 Μεταβλητή2 = 55
Όταν περνάμε μια παράμετρο με αναφορά, θα πρέπει να περνάμε την μεταβλητή και όχι την τιμή της. Συνίσταται να περνούν οι μεταβλητές με αναφορά μόνο όταν απαιτείται η διαδικασία να αλλάξει το περιεχόμενό τους.
Δηλαδή, η παράμετρος θα πρέπει να είναι όνομα μεταβλητής :
swap_vars(global_1, global_2);
και όχι όνομα σταθεράς :
swap_vars(55, 99);
Η συνάρτηση (function) είναι μια διαδικασία που επιστρέφει μία τιμή. Η τιμή αυτή επιστρέφεται στη ρουτίνα που κάλεσε τη συνάρτηση και ονομάζεται αποτέλεσμα της συνάρτησης. Το αποτέλεσμα αυτό χρησιμοποιείται με τον ίδιο τρόπο που χρησιμοποιείται και μια μεταβλητή, μπορεί δηλαδή να είναι μέρος μιας παράστασης, μπορεί να είναι μια πραγματική παράμετρος τιμής ή μπορεί να αποδοθεί σε μια μεταβλητή του ίδιου τύπου.
Οι συναρτήσεις μπορούν να θεωρηθούν ως ένα είδος διαδικασίας. Όλα όσα ειπώθηκαν για τις διαδικασίες, ισχύουν και για τις συναρτήσεις. Εδώ απλά θα δούμε τις διαφορές των συναρτήσεων από τις διαδικασίες. Ακολουθεί ένα πρόγραμμα που περιέχει μια συνάρτηση η οποία υψώνει έναν αριθμό σε κάποια δύναμη.
Program Funct;
Var
num, expo, powr : Real;
Function power(base, exponent : Real) : Real;
Begin
If base >0 Then
Power := Exp(exponent * Ln(base))
Else
Power := -1.0;
End; { end of power() }
Begin
Writeln('Δώστε έναν αριθμό : ');
Readln(num);
Writeln('Δώστε τον εκθέτη : ');
Readln(expo);
powr := Power(num, expo);
Writeln(num, 'Ù', expo, ' = ', powr);
End.
Το παραπάνω πρόγραμμα Funct περιμένει την εισαγωγή δύο αριθμών, της βάσης και του εκθέτη και στη συνέχεια καλεί τη συνάρτηση power, η οποία υψώνει τον αριθμό στην αντίστοιχη δύναμη.
Ο ορισμός μιας συνάρτησης αποτελείται από τρία μέρη : τον τίτλο, τα δεδομένα και το κύριο μέρος της συνάρτησης.
Ο τίτλος της συνάρτησης αποτελείται από τη δεσμευμένη λέξη Function ακολουθούμενη από το όνομα της συνάρτησης καθώς και τις απαιτούμενες παραμέτρους. Η ίδια η συνάρτηση πρέπει να δηλωθεί με κάποιον συγκεκριμένο τύπο δεδομένων.
Τα δεδομένα που πρόκειται να χειριστούν οι εντολές της συνάρτησης, ορισμένα σαν επικεφαλίδες, σταθερές, τύποι και μεταβλητές, δηλώνονται μετά τον τίτλο, αλλά πριν από την πρώτη εντολή της συνάρτησης.
Το κύριο μέρος της συνάρτησης αποτελείται από ένα σύνολο εκτελέσιμων εντολών, όπου περιγράφονται οι πράξεις που πρόκειται να γίνουν. Οι εντολές της συνάρτησης περικλείονται από τις δεσμευμένες λέξεις begin και end ακολουθούμενες από το σύμβολο ;.
Η γενική μορφή της συνάρτησης είναι η εξής :
Τίτλος_Συνάρτησης (Προεραιτικές παράμετροι) : Τύπος_Συνάρτησης;
{Δηλώσεις δεδομένων}
begin
{Εντολές Προγράμματος}
end;
Η κλήση μιας συνάρτησης μπορεί να γίνει γράφοντας μόνο τον τίτλο της. Η συνάρτηση, όμως, επιστρέφει μια τιμή και συνεπώς θα πρέπει μέσα στο κυρίως πρόγραμμα να εκχωρείται η τιμή αυτή σε κάποια μεταβλητή.
Στο παρακάτω παράδειγμα :
powr := power(num, expo);
καλείται η συνάρτηση power και δίνεται η τιμή της στην μεταβλητή powr. Η συνάρτηση power έχει δύο παραμέτρους, που βρίσκονται μέσα σε παρενθέσεις αμέσως μετά το όνομα της συνάρτησης.
Μια συνάρτηση μπορεί επίσης να κληθεί μέσα σε πράξεις, όπως στο παρακάτω παράδειγμα :
dazzle := 12 * surprise(730, 88)/2;
Εδώ η συνάρτηση surprise εκφράζεται ως μέρος μιας πράξης στο δεξί μέρος της εκχώρησης.
Επιστρεφόμενες Τιμές Συναρτήσεων
Η συνάρτηση επιστρέφει κάποια τιμή η οποία περιέχεται στο όνομά της. Για παράδειγμα, η παρακάτω πρόταση :
power := -1.0
αναγκάζει τη συνάρτηση να επιστρέψει την τιμή -1.0. Επίσης η μεταβλητή που δέχεται την τιμή θα πρέπει να είναι του ίδιου τύπου με τον τύπο επιστροφής της συνάρτησης.
Ο ορισμός μιας συνάρτησης είναι πανομοιότυπος μ’ αυτόν μιας διαδικασίας. Η μόνη διαφορά είναι ότι αντί για τη δεσμευμένη λέξη Procedure χρησιμοποιείται η δεσμευμένη λέξη Function και ακόμη θα πρέπει να δηλωθεί και ο τύπος δεδομένων της τιμής επιστροφής της συνάρτησης με το σύμβολο : μετά από τις παραμέτρους.
Ας υποθέσουμε ότι θέλουμε να δώσουμε (διαβάσουμε, read) τιμές σε 5.000 ακεραίους αριθμούς (integers) και να κάνουμε κάποιες πράξεις μαζί τους. Πώς θα πρέπει να αποθηκεύσουμε αυτούς τους αριθμούς; Μια λύση θα ήταν να χρησιμοποιήσουμε 5.000 διαφορετικές μεταβλητές (variables), ως εξής;
aa, ab, ac, ad, ... aaa, aab, ... aba, ...
και μια άλλη λύση θα ήταν να χρησιμοποιήσουμε έναν πίνακα ή διάταξη ή μεταβλητή με δείκτη (array).
Ένας πίνακας (array) περιέχει πολλές θέσεις αποθήκευσης, που είναι όλες του ίδιου τύπου δεδομένων. Μπορούμε να αναφερόμαστε σε μια θέση αποθήκευσης με το όνομα του πίνακα και με την τιμή ενός δείκτη.
Ο ορισμός του πίνακα γίνεται ως εξής :
type
typename = array [enumerated_type] of another_data_type;
Ο τύπος δεδομένων (data type) μπορεί να είναι ο,τιδήποτε, ακόμη κι ένας άλλος πίνακας (array). Κάθε απαριθμητός τύπος (enumerated type) είναι αποδεκτός. Μπορούμε να καθορίσουμε τον απαριθμητό τύπο μέσα στις αγκύλες ή μπορούμε να χρησιμοποιήσουμε έναν προκαθορισμένο απαριθμητό τύπο.
Αυτό σημαίνει ότι η παρακάτω δήλωση :
type
enum_type = 1..50;
arraytype = array [enum_type] of integer;
είναι ισοδύναμη με την εξής :
type
arraytype = array [1..50] of integer;
Για να δηλώσουμε ένα string (συμβολοσειρά), γράφουμε τα εξής :
type
String = packed array [0..255] of char;
Ο όρος packed σημαίνει ότι ο πίνακας (array) θα συμπιεσθεί ώστε να καταλαμβάνει τον μικρότερο δυνατό χώρο μνήμης.
Οι πίνακες είναι ιδιαίτερα χρήσιμοι όταν θέλουμε να αποθηκεύσουμε μεγάλες ποσότητες δεδομένων για να τις χρησιμοποιήσουμε αργότερα μέσα στο πρόγραμμα. Εργάζονται εξαιρετικά καλά με τους βρόχους for. Για παράδειγμα, για να διαβάσουμε 50 αριθμούς, κάνουμε πρώτα τις δηλώσεις :
type arraytype = array[1..50] of integer;
και
var myarray : arraytype;
και γράφουμε μετά την εντολή :
for count := 1 to 50 do
read (myarray[count]);
Χρησιμοποιούμε τις αγκύλες [ ] για να περικλείσουμε τον δείκτη (subscript) όταν αναφερόμαστε σε πίνακες (arrays).
myarray[5] := 6;
Οι Βρόχοι (Loops)
Ο βρόχος (loop) είναι η συνεχής επανάληψη μίας μόνο εντολής ή και μιας ομάδας εντολών μέχρις ότου να ισχύσει μια συνθήκη (condition).
Υπάρχουν τρία είδη βρόχων :
Η επανάληψη ενός βρόχου για έναν καθορισμένο αριθμό φορών.
Ο έλεγχος μιας λογικής έκφρασης (συνθήκης) αρχικά και αν αυτή είναι αληθής (true), τότε ακολουθεί η εκτέλεση ενός βρόχου.
Η εκτέλεση ενός βρόχου για μία τουλάχιστον φορά αρχικά και μετά ακολουθεί ο έλεγχος μιας λογικής έκφρασης (συνθήκης).
Ο Βρόχος For
Στην Pascal, η επανάληψη ενός βρόχου για έναν καθορισμένο αριθμό φορών γίνεται με την εντολή for, η γενική σύνταξη της οποίας είναι η εξής :
for index := ΑρχικήΧαμηλήΤιμή to ΤελικήΥψηλήΤιμή do
εντολή;
Η τιμή της μεταβλητής του δείκτη (index variable) θα πρέπει να είναι ενός βαθμωτού (ordinal) τύπου δεδομένων. Μπορούμε να χρησιμοποιήσουμε τον δείκτη σε υπολογισμούς μέσα στο σώμα ενός βρόχου, αλλά δεν πρέπει να αλλάξουμε την τιμή του.
Ακολουθεί ένα παράδειγμα χρήσης του δείκτη (index) :
sum := 0;
for count := 1 to 100 do
sum := sum + count;
Σ’ έναν βρόχο for-to-do, η αρχική τιμή θα πρέπει να είναι μικρότερη από την τελική τιμή, διαφορετικά ο βρόχος δεν θα εκτελεσθεί ποτέ. Αν θέλουμε να μετρήσουμε ανάποδα, θα πρέπει να χρησιμοποιήσουμε τον βρόχο for-downto-do, ο οποίος έχει την εξής σύνταξη :
for index := ΑρχικήΥψηλήΤιμή downto ΤελικήΧαμηλήΤιμή do
εντολή;
Στην Pascal, με τον βρόχο for μπορούμε να έχουμε βήμα μόνο κατά 1.
Ο Βρόχος While … Do
Ο βρόχος while … do έχει την εξής σύνταξη :
while ΛογικήΈκφραση do
εντολή;
Ο βρόχος συνεχίζει να εκτελείται μέχρις ότου γίνει ψευδής (false) η λογική έκφραση. Μέσα στο σώμα του βρόχου θα πρέπει με κάποιον τρόπο να επηρεάσουμε την λογική έκφραση αλλάζοντας τιμή σε κάποια από τις μεταβλητές που υπάρχουν εκεί. Αλλιώς, θα έχουμε έναν ατέρμονα βρόχο, σαν τον εξής :
a := 5;
while a < 6 do
writeln (a);
Ο παραπάνω βρόχος δεν θα σταματήσει ποτέ να εκτελείται (ατέρμονας) και αυτό γιατί η μεταβλητή a, που χρησιμοποιείται στην λογική έκφραση του βρόχου, δεν αλλάζει πουθενά τιμή μέσα στον βρόχο και έτσι η λογική έκφραση είναι πάντα αληθής (true).
Μπορούμε να διορθώσουμε αυτήν την κατάσταση, αν αλλάξουμε τιμή στην μεταβλητή μέσα στον βρόχο, ως εξής :
a := 5;
while a < 6 do begin
writeln (a);
a := a + 1
end;
Ο βρόχος while … do είναι γνωστός και ως pretest loop επειδή η συνθήκη ελέγχεται πριν εκτελεσθεί έστω και μία φορά το σώμα του βρόχου. Αυτό σημαίνει ότι αν η συνθήκη (λογική έκφραση) είναι ψευδής (false) από την αρχή, το σώμα του βρόχου while δεν θα εκτελεσθεί ποτέ.
Ο Βρόχος Repeat … Until
Ο βρόχος repeat … until έχει την εξής σύνταξη :
repeat
εντολή1;
εντολή2
until ΛογικήΈκφραση;
Στον βρόχο αυτόν δεν χρειάζεται μα χρησιμοποιήσουμε τον συνδυασμό begin end στην περίπτωση που έχουμε περισσότερες από μία εντολές. Ο βρόχος συνεχίζει να εκτελείται έως ότου η λογική έκφραση γίνει αληθής (true), σε αντίθεση με τον βρόχο while, ο οποίος συνεχίζει να εκτελείται για όσο διάστημα η λογική έκφραση παραμένει αληθής (true).
Αυτός ο βρόχος είναι γνωστός και ως posttest loop επειδή η συνθήκη ελέγχεται αφού έχει εκτελεσθεί το σώμα του βρόχου και είναι χρήσιμος όταν θέλουμε να εκτελεσθεί ο βρόχος μία φορά τουλάχιστον, άσχετα με την αρχική τιμή της λογικής έκφρασης. Ακολουθεί ένα παράδειγμα :
Program Trepeat;
Var
metritis : Integer;
Begin
Clrscr;
metritis := 0;
Repeat
Writeln('Μετρητής = ', metritis);
metritis := metritis + 2;
Until (metritis > 4);
End.
Οι Εγγραφές (Records)
Μια εγγραφή (record) μας δίνει την δυνατότητα να έχουμε συσχετισμένα δεδομένα σε μία κοινή δομή. Για να δηλώσουμε μια εγγραφή (record), χρησιμοποιούμε την εξής σύνταξη :
TypeName = record
identifierlist1 : datatype1;
...
identifierlistn : datatypen;
end;
Για παράδειγμα, αν θέλουμε να συγκεντρώσουμε πληροφορίες για ένα άτομο, όπως όνομα, ηλικία, πόλη κατοικίας, ΤΚ κ.ά., μπορούμε να δημιουργήσουμε μια εγγραφή ως εξής :
type
InfoType = record
Name : string;
Age : integer;
City, State : String;
Zip : integer;
end;
Το καθένα από τα αναγνωριστικά (identifiers) Name, Age, City, State και Zip είναι γνωστό και ως πεδίο (field). Μπορούμε να έχουμε πρόσβαση σ’ ένα πεδίο μέσω μιας μεταβλητής ως εξής :
VariableIdentifier.FieldIdentifier
Μια τελεία ξεχωρίζει την μεταβλητή από το όνομα του πεδίου. Υπάρχει μια πολύ χρήσιμη εντολή όταν ασχολούμαστε με records. Αν σκοπεύουμε να χρησιμοποιήσουμε μια μεταβλητή record για να αναφερθούμε σε πολλά πεδία που ανήκουν σ’ αυτό το record και δεν θέλουμε να γράφουμε το ίδιο όνομα συνέχεια, μπορούμε να χρησιμοποιήσουμε την εντολή with, ως εξής :
with RecordVariable do
begin
...
end;
Ακολουθεί ένα παράδειγμα :
with Info do
begin
Age := 18;
ZIP := 90210;
end;
Οι Δείκτες (Pointers) στην Pascal
Ένας δείκτης (pointer) είναι ένας τύπος δεδομένων που περιέχει μια διεύθυνση μνήμης και για να έχουμε πρόσβαση στα δεδομένα που είναι αποθηκευμένα σ’ αυτήν την διεύθυνση μνήμης θα πρέπει να αναφερθούμε στον δείκτη. Για να δηλώσουμε έναν τύπο δεδομένων pointer, θα πρέπει να καθορίσουμε σε ποιο τύπο δεδομένων θα δείχνει. Αυτός ο τύπος δεδομένων θα πρέπει να έχει μπροστά του το σύμβολο (Ù). Για παράδειγμα, για να δημιουργήσουμε έναν δείκτη σε ακέραιο (integer), θα πρέπει να γράψουμε τον εξής κώδικα :
PointerType =Ùinteger;
Θα μπορούμε μετά να δηλώσουμε μεταβλητές που να είναι του τύπου (type) PointerType, ως εξής :
PointerVariable : PointerType;
Πριν αποκτήσουμε πρόσβαση σ’ έναν δείκτη, θα πρέπει να δεσμεύσουμε χώρο στη μνήμη γι’ αυτόν με την εντολή New, ως εξής :
New(PointerVariable);
Για να έχουμε πρόσβαση στα δεδομένα που
βρίσκονται στην θέση μνήμης του δείκτη, θα πρέπει να προσθέσουμε το σύμβολο
Ù
μετά από το όνομα της μεταβλητής. Για παράδειγμα, αν η μεταβλητή
PointerVariable
έχει δηλωθεί ότι είναι του τύπου δεδομένων
PointerType,
μπορούμε να εκχωρήσουμε μια τιμή στην θέση μνήμης ως εξής :
PointerVariableÙ
:= 5;
Αφού έχουμε τελειώσει τη δουλειά μας μ’ έναν δείκτη, θα πρέπει να αποδεσμεύσουμε τον χώρο μνήμης που του έχει εκχωρηθεί, αλλιώς κάθε φορά που εκτελείται το πρόγραμμα, θα ξοδεύεται άσκοπα όλο και περισσότερη μνήμη. Για την αποδέσμευση της μνήμης, χρησιμοποιούμε την εντολή Dispose, ως εξής :
Dispose(PointerVariable);
Ένας δείκτης μπορεί να εκχωρηθεί σ’ έναν άλλον δείκτη. Όμως, εφόσον αντιγράφεται μόνο η διεύθυνση και όχι η τιμή, αν τροποποιηθούν τα δεδομένα που είναι αποθηκευμένα σ’ έναν δείκτη, τότε και ο άλλος δείκτης θα δείχνει στα καινούργια τροποποιημένα δεδομένα. Επίσης, αν καταργήσουμε έναν δείκτη, τότε ο άλλος δείκτης θα δείχνει σε ασυνάρτητα δεδομένα.
Για τι πράγμα είναι καλός ένας δείκτης;
Η χρησιμότητα των δεικτών είναι στην δημιουργία δομών δεδομένων που έχουν δυναμικό μέγεθος (dynamically-sized data structures). Ας δούμε ένα παράδειγμα. Αν θέλουμε να αποθηκεύσουμε πολλά στοιχεία του ίδιου τύπου δεδομένων στην σειρά, μπορούμε να χρησιμοποιήσουμε έναν πίνακα (array). Όμως, ο πίνακάς μας έχει ένα προκαθορισμένο μέγεθος και αν δεν έχουμε δηλώσει ένα αρκετά μεγάλο μέγεθος, ίσως δεν μπορέσουμε να αποθηκεύσουμε όλα τα δεδομένα.
Αν έχουμε δημιουργήσει έναν πολύ μεγάλο πίνακα, τότε θα καταλαμβάνουμε πολύ μνήμη η οποία δεν θα χρησιμοποιείται πάντα. Μια δυναμική δομή δεδομένων, από την άλλη πλευρά, καταλαμβάνει τόση μνήμη όση ακριβώς χρειάζεται και χρησιμοποιείται. Αυτό που πρέπει να κάνουμε είναι να δημιουργήσουμε έναν τύπο δεδομένων που να δείχνει σε μια εγγραφή (record) και η ίδια η εγγραφή να περιέχει αυτόν τον τύπο δεδομένων pointer ως ένα από τα πεδία της (fields).
Για παράδειγμα, οι σωροί (stacks) και οι ουρές (queues) μπορούν να υλοποιηθούν χρησιμοποιώντας την εξής δομή δεδομένων (data structure) :
Type
PointerType = ÙRecordType;
RecordType = record;
data : integer;
next : PointerType;
end;
Το κάθε στοιχείο δείχνει στο επόμενο. Για να γνωρίζουμε πότε έχουμε φθάσει στο τέλος της αλυσίδας των εγγραφών, θα πρέπει στο τελευταίο πεδίο next να εκχωρηθεί η τιμή Nil.
Η Είσοδος Δεδομένων (Input)
Η είσοδος (input) σημαίνει το διάβασμα δεδομένων στην μνήμη από το πληκτρολόγιο, το ποντίκι ή και από ένα αρχείο στον δίσκο και γίνεται με τις εντολές read() και readln(). Η βασική σύνταξη για το διάβασμα δεδομένων είναι η εξής :
read(Variable_List);
Το Variable_List είναι μια σειρά από αναγνωριστικά μεταβλητών χωρισμένα με κόμματα. Η εντολή read, όμως, δεν πηγαίνει στην επόμενη γραμμή. Για να μπορούμε να διαβάσουμε δεδομένα και να πάμε και στην επόμενη γραμμή, χρησιμοποιούμε την εξής εντολή :
readln(Variable_List);
Η Έξοδος Δεδομένων (Output)
Για να γράψουμε (εμφανίσουμε) δεδομένα στην οθόνη, υπάρχουν επίσης δύο εντολές :
write(Argument_List);
writeln(Argument_List);
Η εντολή writeln() πηγαίνει στην επόμενη γραμμή αφού έχει τελειώσει τη δουλειά της, ενώ η εντολή write() παραμένει στην τελευταία θέση της εκτύπωσης για να συνεχίσει από εκεί η επόμενη εντολή write() ή writeln().
Η βασική σύνταξη για να διαβάσουμε από ή να γράψουμε σ’ ένα αρχείο είναι η εξής :
read(file_variable, argument_list);
write(file_variable, argument_list);
Τα ίδια ισχύουν και για τις εντολές readln και writeln. Επίσης, θα πρέπει να δηλώσουμε μια μεταβλητή αρχείου (file variable) στο τμήμα δήλωσης μεταβλητών (variable section), ως εξής :
var
filein, fileout : text;
Ο τύπος δεδομένων text αναφέρεται σε αρχεία κειμένου ή σειριακά αρχεία, δηλ. αρχεία που δεν έχουν δομή από εγγραφές και πεδία, αλλά μόνο σειρές δεδομένων οι οποίες τελειώνουν με τον χαρακτήρα enter, που έχει τον ASCII κώδικα 13.
Ένα αρχείο κειμένου μπορούμε να το ανοίξουμε είτε μόνο για να διαβάσουμε απ’ αυτό είτε μόνο για να γράψουμε σ’ αυτό. Αν θέλουμε να διαβάσουμε απ’ αυτό, θα πρέπει πρώτα να το ανοίξουμε και να πάμε στην αρχή του με την εξής εντολή :
reset(file_variable, 'filename.extension');
Ενώ για να το ανοίξουμε αν θέλουμε να γράψουμε σ’ αυτό, δίνουμε την εξής εντολή :
rewrite(file_variable, 'filename.extension');
Ένα αρχείο που ανοίγει με την εντολή reset μπορεί μόνο να χρησιμοποιηθεί με τις εντολές read και readln, ενώ ένα αρχείο που ανοίγει με την εντολή rewrite μπορεί μόνο να χρησιμοποιηθεί με τις εντολές write και writeln. Πρέπει να έχουμε υπόψη μας ότι ένα αρχείο που ανοίγει μόνο για γράψιμο με την εντολή rewrite χάνει ό,τι περιεχόμενο είχε μέχρι εκείνη την στιγμή.
Αν δουλεύουμε με την Turbo Pascal, η παραπάνω διαδικασία γίνεται διαφορετικά. Πρώτα εκχωρούμε (assign) ένα όνομα αρχείου (filename) σε μια μεταβλητή και μετά δίνουμε μια από τις εντολές reset ή rewrite χρησιμοποιώντας μόνο την μεταβλητή του αρχείου, ως εξής :
assign(file_variable, 'filename.extension');
reset(file_variable)
Δεν θα πρέπει να ξεχνάμε να κλείνουμε τα αρχεία μας πριν τελειώσει το πρόγραμμα, ως εξής :
close(File_Identifier);
Ακολουθεί ένα παράδειγμα προγράμματος που χρησιμοποιεί αρχεία. Αυτό το πρόγραμμα γράφτηκε για Turbo Pascal και DOS και δημιουργεί το αρχείο file2.txt, όπου ο πρώτος χαρακτήρας του (byte) προέρχεται από το αρχείο file1.txt :
program CopyOneByteFile;
var
mychar : char;
filein, fileout : text;
begin
assign(filein, 'c:\file1.txt');
reset(filein);
assign(fileout, 'c:\file2.txt');
rewrite(fileout);
read(filein, mychar);
write(fileout, mychar);
close(filein);
close(fileout)
end.
Ένα δυαδικό αρχείο (binary file) περιέχει δεδομένα αποθηκευμένα στον δίσκο. Τα δυαδικά αρχεία παρέχουν βέλτιστη αποθήκευση αριθμών, λογικών και απαριθμητών τύπων. Για παράδειγμα, για την αποθήκευση του ακέραιου αριθμού 21000 σ’ ένα αρχείο κειμένου θα χρειαστεί ένα string μήκους τουλάχιστον πέντε χαρακτήρων, ενώ για την αποθήκευση του ίδιου αριθμού σ’ ένα δυαδικό αρχείο θα χρειαστούν μόνο δύο χαρακτήρες.
Ένα δυαδικό αρχείο μπορεί να προσπελαστεί είτε σαν αρχείο καθορισμένου ή μη καθορισμένου τύπου. Ένα αρχείο καθορισμένου τύπου περιέχει μια σειρά από διακεκριμένα στοιχεία όπου κάθε στοιχείο πρέπει να είναι του ίδιου τύπου, ο οποίος υποστηρίζεται από την Pascal και αποτελεί συνήθως μια εγγραφή. Ένα αρχείο μη καθορισμένου τύπου χειρίζεται σαν μια μη δομημένη σειρά από bytes. Οι διαδικασίες εισόδου/εξόδου δεν μπορούν να χρησιμοποιηθούν σε αρχεία μη καθορισμένου τύπου. Αντί αυτών πρέπει να χρησιμοποιηθούν δύο άλλες διαδικασίες, οι BlockRead και BlockWrite. Θα δούμε μόνο τα αρχεία καθορισμένου τύπου.
Όπως ένας πίνακας έτσι και ένα αρχείο καθορισμένου τύπου (ΚΤ) αποτελείται από μια σειρά στοιχείων του ίδιου τύπου. Σε αντίθεση, όμως, με τον πίνακα, ένα αρχείο καθορισμένου τύπου δεν έχει καθορισμένο μέγεθος, αρχίζει με μήκος 0 bytes και αυξάνεται αυτόματα προσθέτοντας δεδομένα.
Η δομή ενός τέτοιου αρχείου επιτρέπει την τυχαία προσπέλαση, δηλ. μπορούμε να προσπελάσουμε άμεσα μια εγγραφή του αρχείου χωρίς να χρειαστεί να διαβάσουμε όσες προηγούνται αυτής, όπως γίνεται με τα αρχεία κειμένου.
Δήλωση Αρχείων Καθορισμένου Τύπου
Ένα αρχείο καθορισμένου τύπου περιέχει δεδομένα του τύπου που έχει καθορισθεί στην δήλωση του αρχείου. Η σύνταξη των αρχείων ΚΤ είναι όμοια μ’ αυτή των πινάκων :
File of Τύπος_Στοιχείων_Αρχείου
Ο Τύπος_Στοιχείων_Αρχείου μπορεί να είναι οποιοσδήποτε έγκυρος τύπος δεδομένων, αλλά μ’ έναν περιορισμό : δεν μπορεί να είναι τύπου αρχείου ένας τύπος ο οποίος περιέχει έναν τύπο αρχείου. Ο τύπος των στοιχείων αποτελεί συχνά μία εγγραφή (record).
Ακολουθεί ένα παράδειγμα που δημιουργεί έναν τηλεφωνικό κατάλογο για πολλά πρόσωπα :
Type
phone_rec = RECORD
name : String[20];
long_distance : Boolean;
phone : LongInt;
end; { record }
phone_catalog = File of phone_rec;
math_file = File of Array[1..10] of Real;
Var
master_catalog : Array[1..20] of phone_catalog;
file_phone : phone_catalog;
lucky_numbers : File of Integer;
Ανάγνωση Αρχείων Καθορισμένου Τύπου
Σε αρχεία καθορισμένου τύπου τα δεδομένα δεν αποθηκεύονται με ξεχωριστούς χαρακτήρες Τέλους-Γραμμής και κατά συνέπεια οι διαδικασίες Readln και Writeln δεν μπορούν να χρησιμοποιηθούν και χρησιμοποιούνται μόνο οι διαδικασίες Read και Write. Οι εντολές Assign, Reset και Rewrite λειτουργούν με τον ίδιο τρόπο όπως και με τα αρχεία κειμένου.
Ακολουθεί ένα παράδειγμα προγράμματος :
Var
int_file : File of Integer;
begin
Assign(int_file, 'B:\myfile.dat');
Reset(int_file);
...
Αφού ανοιχθεί το αρχείο, μπορεί να διαβαστεί και να γραφεί οποιοσδήποτε αριθμός στοιχείων σειριακά, με τις διαδικασίες Read και Write. Κάθε στοιχείο που διαβάζεται ή γράφεται, πρέπει να είναι μια μεταβλητή Τύπου_Στοιχείων. Με τα αρχεία καθορισμένου τύπου μπορούμε να χρησιμοποιήσουμε τις παρακάτω διαδικασίες, εκτός από τις διαδικασίες των αρχείων κειμένου :
Διαδικασία Περιγραφή
FilePos Δέχεται ως παράμετρο μια μεταβλητή αρχείου και επιστρέφει την τρέχουσα θέση του αρχείου.
FileSize Δέχεται ως παράμετρο μια μεταβλητή αρχείου και επιστρέφει το μέγεθος του αρχείου σε bytes σ’ έναν αριθμό τύπου LongInt.
Seek Δέχεται ως παράμετρο μια μεταβλητή αρχείου και έναν ακέραιο τύπου LongInt και μεταφέρει την τρέχουσα θέση του αρχείου σε συγκεκριμένο στοιχείο ή τμήμα.
Truncate Δέχεται ως παράμετρο μια μεταβλητή αρχείου και αποκόπτει το μέγεθος του αρχείου στην τρέχουσα θέση του δείκτη του αρχείου. Αυτόματα η Eof γίνεται True.
Οι διαδικασίες τυχαίας προσπέλασης μπορούν να χρησιμοποιηθούν μ’ οποιοδήποτε αρχείο καθορισμένου τύπου. Τυχαία προσπέλαση (random access) είναι η δυνατότητα ανάγνωσης ή εγγραφής στοιχείων οπουδήποτε μέσα στο αρχείο. Οι δύο βασικές διαδικασίες για την τυχαία προσπέλαση είναι η Seek και η FilePos. Το πρώτο στοιχείο του αρχείου είναι το μηδέν, το δεύτερο είναι το ένα κ.ο.κ.
Η σύνταξη της διαδικασίας Seek είναι η ακόλουθη :
Seek(Μεταβλητή_Αρχείου, Θέση_Δείκτη_Αρχείου)
Ακολουθεί ένα παράδειγμα :
Type
phone_rec = RECORD
name, notes : String;
number : LongInt;
end; { record }
Var
phone_list : File of phone_rec;
rec_10, rec_11, rec_15, rec_25 : phone_rec;
Begin
Assign(phone_list, 'phone.dat');
Reset(phone_list);
Seek(phone_list, 9);
Read(phone_list, rec_10, rec_11);
Seek(phone_list, 14);
Read(phone_list, rec_15);
Seek(phone_list, 24);
Read(phone_list, rec_25);
End.
Βλέπουμε στο παραπάνω πρόγραμμα ότι μπορούμε να έχουμε άμεση πρόσβαση σ’ όποιον αριθμό εγγραφής θέλουμε. Ακολουθεί και ένα πρόγραμμα όπου δίνουμε εμείς τον αριθμό της εγγραφής για να κάνουμε καταχώρηση στοιχείων :
Type
phone_rec = Record
name, notes : String;
number : LongInt;
end; { record }
Var
phone_list : File of phone_rec;
temp_rec : phone_rec;
N : LongInt;
Begin
Assign(phone_list, 'phone.dat');
Reset(phone_list);
Write('Δώστε τον αριθμό της εγγραφής : ');
Readln(N);
Write('Δώστε το όνομα : ');
Readln(temp_rec.name);
Write('Δώστε τον αριθμό τηλεφώνου : ');
Readln(temp_rec.number);
Seek(phone_list, N);
Write(phone_list, temp_rec);
End.
Η προσάρτηση δεδομένων στο τέλος του αρχείου γίνεται ως εξής :
Seek(f, FilePos(f));