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

Σχετικά έγγραφα
Εισαγωγή στον Προγραµµατισµό «C»

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

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

Δομές Δεδομένων (Εργ.) Ακ. Έτος Διδάσκων: Ευάγγελος Σπύρου. Εργαστήριο 3 Επανάληψη Γ μέρος

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

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

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

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

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

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

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

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

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

C: Από τη Θεωρία στην Εφαρµογή 2 ο Κεφάλαιο

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

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

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

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

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

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

ΥΠΟΛΟΓΙΣΤΕΣ ΙΙ. Τι περιλαμβάνει μια μεταβλητή; ΔΕΙΚΤΕΣ. Διεύθυνση μεταβλητής. Δείκτης

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

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

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

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

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

a = 10; a = k; int a,b,c; a = b = c = 10;

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

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

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

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

Προγραμματισμός ΙI (Θ)

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

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

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

ΑΣΚΗΣΗ 5: ΠΙΝΑΚΕΣ. Σχήµα 1: H έννοια των πινάκων

3 ο Εργαστήριο Μεταβλητές, Τελεστές

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΜΑΘΗΜΑ 3 Ο. Σταθερές-Παράμετροι-Μεταβλητές Αριθμητικοί & Λογικοί Τελεστές Δομή ελέγχου-επιλογής Σύνθετοι έλεγχοι

Προγραμματισμός ΙI (Θ)

ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΙΑΣ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ

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

Εισαγωγή στη γλώσσα προγραμματισμού C++

3.1 Αριθμητικοί και Λογικοί Τελεστές, Μετατροπές Τύπου (Casting)

Οικονόμου Βαγγέλησ Διάλεξη Νο 2. Δομημένοσ Προγραμματιςμόσ - Διάλεξη 2

Κεφάλαιο ΙV: Δείκτες και πίνακες. 4.1 Δείκτες.

ΚΕΦΑΛΑΙΟ 8 Η ΓΛΩΣΣΑ PASCAL

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

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

Η πρώτη παράμετρος είναι ένα αλφαριθμητικό μορφοποίησης

Προγραμματισμός Η/Υ 1 (Εργαστήριο)

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

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

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

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

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

Υπολογισμός - Συλλογή Δεδομένων - Πίνακες

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

Πίνακες. 1 Πίνακες. 30 Μαρτίου 2014

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

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

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

2ο ΓΕΛ ΑΓ.ΔΗΜΗΤΡΙΟΥ ΑΕΠΠ ΘΕΟΔΟΣΙΟΥ ΔΙΟΝ ΠΡΟΣΟΧΗ ΣΤΑ ΠΑΡΑΚΑΤΩ

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

Προγραμματιστικό Περιβάλλον

Τμήμα Πληροφορικής & Επικοινωνιών Δρ. Θεόδωρος Γ. Λάντζος

Βασικοί τύποι δεδομένων (Pascal) ΕΠΑ.Λ Αλίμου Γ Πληροφορική Δομημένος Προγραμματισμός (Ε) Σχολ. Ετος Κων/νος Φλώρος

Προγραμματισμός Η/Υ Ι (Χρήση της C) 6 η Θεωρία ΜΟΝΟΔΙΑΣΤΑΤΟΙ ΠΙΝΑΚΕΣ

Εισαγωγή στη γλώσσα προγραμματισμού C++14

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

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

ΒΑΣΙΚΟΙ ΤΥΠΟΙ ΔΕΔΟΜΕΝΩΝ

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

ΓΛΩΣΣΑ ΑΛΦΑΒΗΤΟ ΤΥΠΟΙ ΔΕΔΟΜΕΝΩΝ ΣΤΑΘΕΡΕΣ ΜΕΤΑΒΛΗΤΕΣ

Στόχοι και αντικείμενο ενότητας. Εκφράσεις. Η έννοια του τελεστή. #2.. Εισαγωγή στη C (Μέρος Δεύτερο) Η έννοια του Τελεστή

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

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

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

Η-Υ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ. Εργαστήριο 2 Εντολές Εισόδου/Εξόδου Τελεστές. Δρ. Γιώργος Λαμπρινίδης 23/10/2015 Η - Υ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ 1

ΑΝΑΠΤΥΞΗ ΕΦΑΡΜΟΓΩΝ Κεφάλαιο 2 ο

5ο σετ σημειώσεων - Δείκτες

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

Διάλεξη 6: Δείκτες και Πίνακες

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

Τμήμα Πληροφορικής & Επικοινωνιών Δρ. Θεόδωρος Γ. Λάντζος

Ρητή μετατροπή αριθμητικής τιμής σε άλλο τύπο. Τι θα τυπωθεί στον παρακάτω κώδικα;

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

Δυναμικές Ιστοσελίδες Εισαγωγή στην Javascript για προγραμματισμό στην πλευρά του client

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

ΠΛΗΡΟΦΟΡΙΚΗ I. 4 η ΔΙΑΛΕΞΗ Αριθμητικά Συστήματα

ΠΛΗΡΟΦΟΡΙΚΗ Ι JAVA Τμήμα θεωρίας με Α.Μ. σε 3, 7, 8 & 9 25/10/07

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

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

2 ΟΥ και 7 ΟΥ ΚΕΦΑΛΑΙΟΥ

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

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

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

7. Βασικά στοιχεία προγραµµατισµού.

8 FORTRAN 77/90/95/2003

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

for for for for( . */

Transcript:

Τμήμα ΜΗΧΑΝΙΚΩΝ ΠΛΗΡΟΦΟΡΙΚΗΣ ΤΕ ΤΕΙ ΔΥΤΙΚΗΣ ΕΛΛΑΔΑΣ Διαδικασιακός Προγραμματισμός Διάλεξη 8 η Δείκτες Οι διαλέξεις βασίζονται στο βιβλίο των Τσελίκη και Τσελίκα C: Από τη Θεωρία στην Εφαρμογή Σωτήρης Χριστοδούλου Μνήμη Υπολογιστή Η μνήμη RAM (Random Access Memory) ενός υπολογιστή αποτελείται από πολλές χιλιάδες θέσεις αποθήκευσης δεδομένων που έχουν διαδοχική αρίθμηση Κάθε θέση ή κελί μνήμης προσδιορίζεται από μία μοναδική διεύθυνση Η διεύθυνση της κάθε θέσης μνήμης είναι ένας αύξοντας αριθμός με τιμή που κυμαίνεται από το 0 έως μία μέγιστη τιμή (η οποία εξαρτάται από το μέγεθος της διαθέσιμης μνήμης στον συγκεκριμένο υπολογιστή) Το περιεχόμενο της κάθε θέσης μνήμης είναι ένας ακέραιος αριθμός με μέγεθος 1 byte 2 1

Μνήμη Υπολογιστή και Μεταβλητές Όταν δηλώνεται μία μεταβλητή, ο μεταγλωττιστής δεσμεύει τις απαραίτητες συνεχόμενες θέσεις (bytes) στη μνήμη, για να αποθηκεύσει την τιμή της Όπως ήδη ξέρουμε, κάθε τύπος μεταβλητής απαιτεί συγκεκριμένο χώρο στη μνήμη Π.χ. ο τύπος char απαιτεί 1 byte μνήμης, οι τύποι float και int απαιτούν 4 bytes, ο τύπος double απαιτεί 8 bytes, κ.ο.κ. Όταν μία μεταβλητή καταλαμβάνει πολλές θέσεις μνήμης (δηλ. περισσότερα από 1 byte), τότε ως διεύθυνση της μεταβλητής θεωρείται η διεύθυνση της πρώτης θέσης μνήμης (δηλ. του 1ου byte από τα bytes που καταλαμβάνει η μεταβλητή) 3 Παράδειγμα Έστω η δήλωση: int a; Τότε: Ο μεταγλωττιστής ψάχνει και βρίσκει 4 συνεχόμενες θέσεις μνήμης στη RAM, οι οποίες δεν πρέπει να έχουν δεσμευτεί για άλλη μεταβλητή, και τις δεσμεύει Σε αυτές τις θέσεις θα αποθηκεύεται η τιμή της μεταβλητής a Στο διπλανό σχήμα θεωρούμε ότι η διεύθυνση της μεταβλητής a αρχίζει στη θέση 100 Η τιμή της a θα αποθηκευτεί στις θέσεις μνήμης από 100 έως και 103 Ο μεταγλωττιστής συσχετίζει το όνομα της μεταβλητής a, με τη διεύθυνση της μεταβλητής Όταν το πρόγραμμα χρησιμοποιεί το όνομα της μεταβλητής, ο μεταγλωττιστής προσπελαύνει αυτομάτως τη διεύθυνση της μεταβλητής Π.χ. με την εντολή a = 10; ο μεταγλωττιστής γνωρίζει ότι η διεύθυνση της a είναι η 100 και θέτει το περιεχόμενό της ίσο με 10, ξεκινώντας από την οκτάδα με την μεγαλύτερη διεύθυνση 4 2

Δήλωση Δείκτη Ο δείκτης είναι μία αριθμητική μεταβλητή, στην οποία αποθηκεύεται η διεύθυνση μνήμης μίας άλλης μεταβλητής Η γενική περίπτωση δήλωσης ενός δείκτη είναι: τύπος_δεδομένων* όνομα_δείκτη; Παρατηρήσεις O τύπος_δεδομένων μπορεί να είναι οποιοσδήποτε από τους τύπους μεταβλητών της C και δηλώνει τον τύπο της μεταβλητής στην οποία δείχνει ο δείκτης Το όνομα_δείκτη πρέπει να ακολουθεί τους κανόνες ονοματολογίας της C και να μην υπάρχει άλλη δήλωση με το ίδιο όνομα μέσα στο πρόγραμμα Ο τελεστής * χρησιμοποιείται για να δηλώσει ότι η μεταβλητή είναι δείκτης 5 Παραδείγματα Δήλωσης Δείκτη int* ptr; Η μεταβλητή ptr είναι ένας δείκτης προς κάποια ακέραια μεταβλητή Αυτό σημαίνει, ότι στον δείκτη ptr θα αποθηκευτεί η διεύθυνση κάποιας ακέραιας μεταβλητής double* ptr; Η μεταβλητή ptr είναι ένας δείκτης προς κάποια πραγματική μεταβλητή (και μάλιστα, τύπου double) Αυτό σημαίνει, ότι στον δείκτη ptr θα αποθηκευτεί η διεύθυνση κάποιας πραγματικής μεταβλητής (και πιο συγκεκριμένα, μιας μεταβλητής τύπου double) 6 3

Απόδοση τιμής σε Δείκτη Ένας δείκτης, πριν χρησιμοποιηθεί, πρέπει να έχει σαν τιμή τη διεύθυνση κάποιας μεταβλητής ή, ισοδύναμα, να «δείχνει» σε κάποια υπαρκτή μεταβλητή Για να βρούμε τη διεύθυνση κάποιας μεταβλητής χρησιμοποιούμε τον τελεστή διεύθυνσης & πριν από το όνομα της μεταβλητής Υπενθυμίζεται ότι η διεύθυνση είναι η θέση της μεταβλητής στη μνήμη του υπολογιστή και δεν έχει καμία σχέση με την τιμή της μεταβλητής 7 Παρατηρήσεις Για την εμφάνιση στην οθόνη της διεύθυνσης μνήμης μίας μεταβλητής συνήθως χρησιμοποιείται το προσδιοριστικό %p, το οποίο εμφανίζει τη διεύθυνση σε δεκαεξαδική μορφή (μπορούμε να χρησιμοποιήσουμε και το προσδιοριστικό %d, για την εμφάνιση της διεύθυνσης σε δεκαδική μορφή) Όταν εκχωρείται η διεύθυνση μίας μεταβλητής σε έναν δείκτη, ο δείκτης πρέπει να έχει δηλωθεί σαν δείκτης στον ίδιο τύπο με τη μεταβλητή Προσοχή λοιπόν σε λάθη όπως αυτό του παρακάτω παραδείγματος int* ptr; float a; ptr = &a; Η τιμή που εκχωρείται σε έναν δείκτη πρέπει να είναι η διεύθυνση κάποιας υπαρκτής μεταβλητής και όχι μία σταθερή αριθμητική τιμή Στο παρακάτω παράδειγμα ο μεταγλωττιστής θα εμφανίσει μήνυμα λάθους int* ptr; ptr = 1000; 8 4

Η ειδική τιμή NULL (Ι) Υπενθυμίζεται ότι, όταν δηλώνεται μία μεταβλητή, τότε ο μεταγλωττιστής αναθέτει στη μεταβλητή μία τυχαία τιμή (γι αυτό το λόγο ΠΡΕΠΕΙ να αρχικοποιούμε οι ίδιοι τις μεταβλητές μας) Επομένως, όταν δηλώνεται μία μεταβλητή-δείκτης, τότε η αρχική τιμή του δείκτη αυτού είναι μία τυχαία διεύθυνση μνήμης Στο παρακάτω παράδειγμα, εμφανίζεται στην οθόνη η τυχαία τιμή που εκχώρησε ο μεταγλωττιστής στον δείκτη ptr 9 Η ειδική τιμή NULL (ΙΙ) Όταν θέλουμε να δηλώσουμε ρητά ότι ένας δείκτης δεν δείχνει πουθενά, τότε του αναθέτουμε την τιμή NULL Η τιμή NULL είναι μία ειδική τιμή, ίση με το μηδέν Επομένως, το επόμενο παράδειγμα εμφανίζει την τιμή 0 10 5

Παρατηρήσεις Όταν δηλώνεται μία μεταβλητή-δείκτης, ο μεταγλωττιστής, όπως κάνει και για οποιαδήποτε μεταβλητή, δεσμεύει τις απαραίτητες θέσεις μνήμης για να αποθηκεύσει την τιμή του Το επόμενο πρόγραμμα εμφανίζει πόσα bytes μνήμης δεσμεύτηκαν για τον δείκτη ptr με χρήση του τελεστή sizeof() Ta bytes που δεσμεύονται για μία μεταβλητή-δείκτη είναι 4, ανεξάρτητα από τον τύπο δεδομένων στον οποίο δείχνει ο δείκτης Δηλαδή, στο προηγούμενο παράδειγμα είτε έχουμε τη δήλωση char* ptr; ή double* ptr; το αποτέλεσμα είναι 4 11 Χρήση Δείκτη Για να αποκτήσουμε πρόσβαση στο περιεχόμενο κάποιας διεύθυνσης μνήμης με χρήση δείκτη, χρησιμοποιούμε τον τελεστή * πριν από το όνομα του δείκτη Π.χ. 12 6

Δεν ξεχνώ λοιπόν... Δήλωση Μεταβλητών Δήλωση Μεταβλητών Δεικτών Ανάθεση τιμών στους Δείκτες (τις διευθύνσεις υπαρκτών μεταβλητών) Απόδοση τιμής σε κάποια μεταβλητή, μέσω δείκτη (το περιεχόμενο της διεύθυνσης στην οποία δείχνει ο δείκτης) 13 Παρατηρήσεις (Ι) Πριν χρησιμοποιηθεί κάποια μεταβλητή-δείκτης πρέπει να της έχει εκχωρηθεί μία υπαρκτή διεύθυνση, δηλαδή ο δείκτης να δείχνει στη διεύθυνση κάποιας μεταβλητής Το επόμενο πρόγραμμα θα εμφανίσει μήνυμα λάθους κατά την εκτέλεσή του, γιατί στην εντολή i = *ptr; χρησιμοποιείται ο δείκτης ptr, ο οποίος δεν δείχνει στη διεύθυνση κάποιας μεταβλητής 14 7

Παρατηρήσεις (ΙΙ) Το επόμενο πρόγραμμα λειτουργεί σωστά, γιατί τώρα ο δείκτης ptr δείχνει στη διεύθυνση κάποιας υπαρκτής μεταβλητής (της μεταβλητής j) πριν χρησιμοποιηθεί στην εντολή i = *ptr; Επομένως, αφού ο δείκτης ptr δείχνει στη διεύθυνση της μεταβλητής j, το *ptr θα είναι ίσο με την τιμή του j, δηλαδή 10 Άρα, με την εντολή i = *ptr; η τιμή του i θα γίνει ίση με 10 Έξοδος: Value = 10 15 Παρατηρήσεις (ΙΙΙ) Οι τελεστές * (περιεχόμενο διεύθυνσης μνήμης που δείχνει ο δείκτης) και & (διεύθυνση μνήμης μιας μεταβλητής) είναι μεταξύ τους συμπληρωματικοί ή αντίστροφοι (αλλιώς λέμε ότι αλληλοαναιρούνται ή αλληλοεξουδετερώνονται) Έξοδος: The address of a is 0028F958 The value of ptr is 0028F958 The value of a is 21 The value of *ptr is 21 Showing that * and & are complements of each other &*ptr = 0028F958 *&ptr = 0028F958 16 8

Παραδείγματα (Ι) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: 30 17 Παραδείγματα (ΙΙ) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: 25 18 9

Παραδείγματα (ΙΙΙ) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: 11 19 Παραδείγματα (ΙV) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: 0 1 2 20 10

Παραδείγματα (V) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: 200 21 Χρήση της λέξης const στη δήλωση ενός δείκτη Χρησιμοποιούμε τη δεσμευμένη λέξη const κατά τη δήλωση του δείκτη, όταν επιθυμούμε μία μεταβλητή-δείκτης είτε να μην μπορεί να αλλάξει την τιμή της μεταβλητής στην οποία δείχνει είτε να μην μπορεί να δείξει σε κάποια άλλη μεταβλητή Συνεπώς, τα παρακάτω παραδείγματα αποτελούν μη επιτρεπτές ενέργειες Ο δείκτης ptr δεv μπορεί να αλλάξει την τιμή της μεταβλητής στην οποία δείχνει (της i) Ο δείκτης ptr δεv μπορεί να δείξει σε άλλη μεταβλητή (όπως π.χ. εδώ στην j), παρά μόνο στην i 22 11

Αριθμητική Δεικτών Οι αριθμητικοί τελεστές που μπορούν να χρησιμοποιηθούν στην αριθμητική δεικτών είναι οι: ++, --, + και Στην αριθμητική δεικτών, πράξεις όπως η πρόσθεση και η αφαίρεση με ακεραίους αριθμούς έχουν ορισμένες ιδιαιτερότητες και για τον λόγο αυτό, απαιτείται ιδιαίτερη προσοχή 23 Αύξηση Δεικτών Όταν προστίθεται ο αριθμός 1 σε έναν δείκτη, τότε η τιμή του δείκτη αυξάνει σύμφωνα με το μέγεθος του τύπου δεδομένων στον οποίο δείχνει Π.χ. αν ο δείκτης έχει δηλωθεί σαν δείκτης σε: char, τότε η τιμή του δείκτη αυξάνεται κατά 1, αφού ο τύπος char δεσμεύει 1 byte από τη μνήμη int ή float, τότε η τιμή του δείκτη αυξάνεται κατά 4, αφού οι τύποι int και float δεσμεύουν 4 bytes από τη μνήμη double, τότε η τιμή του δείκτη αυξάνεται κατά 8, αφού ο τύπος double δεσμεύει 8 bytes από τη μνήμη Στη γενική περίπτωση, όταν προστίθεται ένας ακέραιος αριθμός n σε έναν δείκτη, τότε η τιμή του αυξάνεται κατά το γινόμενο: n * μέγεθος του τύπου (στον οποίο δείχνει) 24 12

Παράδειγμα Τι εμφανίζει η τελευταία printf() του προγράμματος??? Έξοδος: 1004 (σε δεκαεξαδική μορφή) Αν είχα αντί για ptr++; Την εντολή ptr+=5;??? Έξοδος: 1020 (σε δεκαεξαδική μορφή) 25 Μείωση Δεικτών Ισχύει ακριβώς ό,τι ισχύει και κατά την αύξηση ενός δείκτη Δηλ. στη γενική περίπτωση, όταν αφαιρείται ένας ακέραιος αριθμός n από έναν δείκτη, τότε η τιμή του μειώνεται κατά το γινόμενο: n * μέγεθος του τύπου (στον οποίο δείχνει) Π.χ. Έξοδος: 980 (σε δεκαεξαδική μορφή) 26 13

Αφαίρεση Δεικτών Η αφαίρεση δεικτών, επιτρέπεται μόνο μεταξύ δεικτών, οι οποίοι δείχνουν σε ίδιο τύπο δεδομένων Το αποτέλεσμα της αφαίρεσης είναι ένας ακέραιος αριθμός που δεν δηλώνει πόσο απέχουν μεταξύ τους (δηλ. πόσες θέσεις μνήμης), αλλά πόσα στοιχεία του τύπου που δείχνουν οι δείκτες μεσολαβούν μεταξύ τους 27 Παράδειγμα Τι εμφανίζει η τελευταία printf() του προγράμματος??? Έξοδος: 10 (και όχι 40) 28 14

Αφαίρεση Δεικτών Στη γενική περίπτωση, το αποτέλεσμα της αφαίρεσης δεικτών είναι το πηλίκο της διαίρεσης της αριθμητικής διαφοράς των δύο δεικτών με το μέγεθος του τύπου, στον οποίο δείχνουν Στο προηγούμενο παράδειγμα το αποτέλεσμα προκύπτει ως: (1040 1000) / sizeof(int) = 40/4 = 10 Προφανώς, αν αφαιρέτης είναι ο δείκτης με τη χαμηλότερη διεύθυνση στη μνήμη και αφαιρετέος ο δείκτης με την υψηλότερη διεύθυνση αντίστοιχα, τότε το αποτέλεσμα της αφαίρεσης των δεικτών θα είναι το ίδιο αριθμητικά, με αρνητικό όμως πρόσημο Στο προηγούμενο παράδειγμα αν στην τελευταία printf() ζητούσαμε τη διαφορά ptr1-ptr2, το αποτέλεσμα θα ήταν: (1000 1040) / sizeof(int) = -40/4 = -10 29 Σύγκριση Δεικτών Η σύγκριση δεικτών επιτρέπεται μόνο μεταξύ δεικτών που δείχνουν στον ίδιο τύπο δεδομένων Σε αυτή την περίπτωση, οι σχεσιακοί τελεστές ==,!=, >, <, >= και <= λειτουργούν κανονικά Π.χ., αν θέλουμε να ελέγξουμε αν δύο δείκτες ptr1 και ptr2 δείχνουν στην ίδια διεύθυνση μνήμης μπορούμε να γράψουμε: if(ptr1 == ptr2) ή αντίστοιχα: if(ptr1!= ptr2) Π.χ., αν θέλουμε να ελέγξουμε αν ο δείκτης ptr1 δείχνει σε κάποια μεταβλητή με «μεγαλύτερη» διεύθυνση από την αντίστοιχη που δείχνει ο δείκτης ptr2 μπορούμε να γράψουμε: if(ptr1 > ptr2) 30 15

Παρατηρήσεις Ο μεταγλωττιστής, κατά την αφαίρεση και την πρόσθεση ενός ακέραιου αριθμού σε έναν δείκτη, αλλάζει την τιμή του δείκτη με βάση το μέγεθος του τύπου δεδομένων που δείχνει ο δείκτης Εκτός από την πρόσθεση ή την αφαίρεση ακεραίων αριθμών σε/από έναν δείκτη, τη σύγκριση και την αφαίρεση δεικτών ίδιου τύπου, καμία άλλη αριθμητική πράξη δεν επιτρέπεται Π.χ. οι εντολές: πολλαπλασιασμού ptr *= 2; πρόσθεσης δεκαδικού ptr += 7.5; πρόσθεσης δεικτών ptr1 + ptr2; δεν είναι επιτρεπτές εκφράσεις ακόμα κι αν οι αυτοί δείκτες δείχνουν στον ίδιο τύπο δεδομένων 31 Παραδείγματα (Ι) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: Το τυχαίο περιεχόμενο των επόμενων 4 bytes μετά τη θέση της μεταβλητής i στη μνήμη 32 16

Παραδείγματα (ΙΙ) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: i=40 j=60 k=130 33 Παραδείγματα (ΙII) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: 100 120 150 34 17

Παραδείγματα (ΙV) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: Value = 20 35 Παραδείγματα (V) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: Value = 120 36 18

Παραδείγματα (VI) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: Value = 300 37 Παραδείγματα (VIΙ) Γράψτε ένα πρόγραμμα το οποίο να διαβάζει δύο ακέραιους, τους οποίους να αποθηκεύει σε δύο δείκτες για ακέραιους. Με χρήση αυτών των δεικτών, αποθηκεύστε το άθροισμά τους σε έναν άλλον δείκτη σε ακέραιο και εμφανίστε τα περιεχόμενα του κάθε δείκτη 38 19

Δείκτες και Πίνακες - Εισαγωγή Τα στοιχεία ενός πίνακα αποθηκεύονται σε διαδοχικές θέσεις μνήμης, με το πρώτο στοιχείο στη χαμηλότερη διεύθυνση Τα επόμενα στοιχεία του πίνακα αποθηκεύονται στις υψηλότερες διευθύνσεις Το πόσο υψηλότερα, εξαρτάται από τον τύπο δεδομένων του πίνακα (char, int, float,..) Π.χ. σε έναν πίνακα χαρακτήρων (char), κάθε στοιχείο του πίνακα βρίσκεται 1 byte μετά από το προηγούμενο στοιχείο και η διεύθυνση κάθε στοιχείου είναι 1 θέση υψηλότερα από τη διεύθυνση του προηγούμενου στοιχείου Παρομοίως, σε έναν πίνακα ακεραίων (int), κάθε στοιχείο του πίνακα βρίσκεται 4 bytes μετά από το προηγούμενο στοιχείο και η διεύθυνση κάθε στοιχείου είναι 4 θέσεις υψηλότερα από τη διεύθυνση του προηγούμενου στοιχείου 39 Έστω η δήλωση του πίνακα: Παράδειγμα int arr[3]; Αν θεωρήσουμε ότι η διεύθυνση του πρώτου στοιχείου είναι η θέση 100 στη μνήμη, τότε η διεύθυνση του δεύτερου στοιχείου είναι η 104 και του τρίτου η 108 Αντίστοιχα, η τιμή του πρώτου στοιχείου του πίνακα (του arr[0]) αποθηκεύεται στις θέσεις 100 έως και 103, η τιμή του δεύτερου στοιχείου (του arr[1]) στις θέσεις 104 έως και 107 και η τιμή του τρίτου στοιχείου (του arr[2]) στις θέσεις 108 έως και 111 40 20

Δείκτες και Πίνακες (Ι) Ένα όνομα πίνακα χωρίς αγκύλες είναι ένας δείκτης στο πρώτο στοιχείο του πίνακα Με άλλα λόγια, η τιμή του ονόματος του πίνακα (χωρίς αγκύλες) ισούται με τη διεύθυνση του πρώτου στοιχείου του πίνακα Π.χ. αν έχει δηλωθεί ο πίνακας int arr[100]; τότε η τιμή του arr είναι ίση με τη διεύθυνση του πρώτου στοιχείου του πίνακα (δηλ. ίση με &arr[0]) και αν η μνήμη του υπολογιστή ήταν όπως αυτή του παρακάτω σχήματος, η τιμή τους θα ήταν ίση με 100 Συμπερασματικά, οι εκφράσεις arr και &arr[0] είναι ισοδύναμες 41 Δείκτες και Πίνακες (ΙΙ) Υπενθυμίζεται από την αριθμητική δεικτών, ότι, όταν προστίθεται ένας ακέραιος αριθμός n σε έναν δείκτη, τότε ο δείκτης δείχνει σε μία νέα διεύθυνση που απέχει (σε bytes): n * μέγεθος του τύπου (στον οποίο δείχνει) Βάσει της λογικής αυτής, η έκφραση arr+1 είναι ένας δείκτης που δείχνει στο δεύτερο στοιχείο του πίνακα, άρα οι εκφράσεις arr+1 και &arr[1] είναι ισοδύναμες, αφού και οι δύο είναι ίσες με τη διεύθυνση του δεύτερου στοιχείου του πίνακα, κ.ο.κ. Δηλαδή, γενικά ισχύει ότι: arr == &arr[0] arr + 1 == &arr[1] arr + 2 == &arr[2] arr + n == &arr[n] 42 21

Δείκτες και Πίνακες (ΙΙI) Αφού το όνομα ενός πίνακα είναι δείκτης στη διεύθυνση του πρώτου στοιχείου του, τότε το περιεχόμενό του θα είναι ίσο με την τιμή του πρώτου στοιχείου του Δηλαδή, ισχύει ότι το *arr είναι ίσο με arr[0] Αντίστοιχα, αφού το arr+1 είναι δείκτης στο δεύτερο στοιχείο του πίνακα, τότε ισχύει ότι *(arr+1) είναι ίσο με arr[1], κ.ο.κ. Δηλαδή, γενικά ισχύει ότι (προσοχή στις παρενθέσεις): *arr == arr[0] *(arr + 1) == arr[1] *(arr + 2) == arr[2] *(arr + n) == arr[n] 43 Παράδειγμα (Ι) Πιθανή Έξοδος: 44 22

Παράδειγμα (ΙΙ) Πιθανή Έξοδος: 45 Παρατηρήσεις (Ι) SOS!!!!!! Ποιες είναι οι κύριες διαφορές μεταξύ των δηλώσεων: α) int ptr[100]; και β) int* ptr; 1) Δεσμευμένη μνήμη? α) Πίνακας 100 ακεραίων, άρα: 100 * sizeof(int) = 100 * 4 = 400 bytes β) Ένας απλός δείκτης, άρα: sizeof(ptr) = 4 bytes 2) Πού δείχνουν στη μνήμη? α) Το όνομα του πίνακα χωρίς τις αγκύλες, δηλαδή το ptr, δείχνει στην αρχή αυτής της δεσμευμένης μνήμης Η τιμή του δεν μπορεί να αλλάξει, δηλαδή ΔΕΝ επιτρέπεται να δείξει σε κάποια άλλη διεύθυνση μνήμης β) Ο δείκτης ptr δεν δείχνει σε κάποια διεύθυνση μνήμης Επομένως, πριν χρησιμοποιηθεί, πρέπει να του εκχωρηθεί μία υπαρκτή διεύθυνση, δηλαδή να δείχνει στη διεύθυνση κάποιας μεταβλητής Μετά την αρχική εκχώρηση, η τιμή του μπορεί να αλλάξει, δηλαδή επιτρέπεται να δείξει σε κάποια άλλη διεύθυνση μνήμης 46 23

Παρατηρήσεις (ΙI) SOS!!!!!! Ποιον από τους δύο προηγούμενους τρόπους να χρησιμοποιήσετε? α) int arr[100]; ή β) int* arr; Η απάντηση είναι προφανής... Για τον χειρισμό των στοιχείων ενός πίνακα προτείνεται το πρώτο από τα παραπάνω είδη σύνταξης, στο οποίο αποτυπώνεται εμφανώς η θέση του στοιχείου στον πίνακα και όχι η σύνταξη με τη σημειογραφία δείκτη, γιατί ο κώδικας του προγράμματος είναι περισσότερο ευανάγνωστος και λιγότερο επιρρεπής σε λάθη Δηλαδή, το arr[i] είναι πιο κατανοητό και πιο ασφαλές από το *(arr+i) Π.χ. αν ξεχάσουμε π.χ. τις παρενθέσεις, τότε εισάγεται ένα σφάλμα στον κώδικα (bug) που είναι δύσκολο να εντοπιστεί 47 Παρατηρήσεις (ΙIΙ) Αν ένας δείκτης δείχνει σε κάποιο στοιχείο ενός πίνακα, μπορούμε να χρησιμοποιήσουμε τον δείκτη σαν πίνακα Ωστόσο, να θυμάστε ότι, παρά τη στενή σχέση δεικτών και πινάκων, ένας δείκτης δεν είναι πίνακας Για παράδειγμα, το επόμενο πρόγραμμα εμφανίζει τα στοιχεία ενός πίνακα χρησιμοποιώντας τον δείκτη ptr σαν να ήταν πίνακας 48 24

Παραδείγματα (Ι) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: Val1 = 12 Val2 = 30 49 Παραδείγματα (IΙ) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: Val = 58 50 25

Παραδείγματα (IIΙ) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: 3 51 Παραδείγματα (IV) Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: 30 40 50 (και δύο τυχαίες τιμές) 52 26

Παραδείγματα (V) Υπάρχει κάποιο bug στο παρακάτω πρόγραμμα??? Απάντηση: Όχι... «σκονάκι No1»: θυμηθείτε ότι *(arr+i)= arr[i] Κι άλλη υπόδειξη??? «σκονάκι No2»: *(arr+i)= *(i+arr) Κι άλλο??? «σκονάκι No3»: arr[i]=*(arr+i)= *(i+arr)= i[arr] 53 Πίνακας Δεικτών Ένας πίνακας δεικτών είναι μία ειδική περίπτωση πίνακα, όπου κάθε στοιχείο του πίνακα είναι ένας δείκτης σε έναν συγκεκριμένο τύπο δεδομένων Για να δηλώσουμε έναν πίνακα δεικτών χρησιμοποιούμε τον τελεστή * πριν από το όνομα του πίνακα Π.χ. int* array[10]; Δήλωση ενός πίνακα δεικτών με όνομα array, ο οποίος περιέχει 10 στοιχεία και το καθένα από αυτά είναι ένας δείκτης σε μία ακέραια μεταβλητή (int) char* arr[10]; Δήλωση ενός πίνακα δεικτών με όνομα arr, ο οποίος περιέχει 10 στοιχεία και το καθένα από αυτά είναι ένας δείκτης σε έναν χαρακτήρα (char) 54 27

Παράδειγμα Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: 10 20 30 55 Δείκτης σε Δείκτη Όταν δηλώνεται μία μεταβλητή-δείκτης, ο μεταγλωττιστής, όπως κάνει για οποιαδήποτε μεταβλητή, δεσμεύει τις απαραίτητες θέσεις μνήμης για να αποθηκεύσει την τιμή της Επομένως, αφού έχει δεσμευτεί μία διεύθυνση μνήμης για έναν δείκτη μπορούμε να δηλώσουμε έναν άλλον δείκτη που να δείχνει σε αυτή τη διεύθυνση Για να δηλώσουμε έναν δείκτη σε κάποιον άλλον δείκτη χρησιμοποιούμε δύο φορές τον τελεστή * Παραδείγματα Δηλώσεων «Δείκτη σε Δείκτη» 56 28

Χρήση «Δείκτη σε Δείκτη» Αν έχουμε δηλώσει έναν δείκτη σε έναν δεύτερο δείκτη, τότε με τον τελεστή * έχουμε πρόσβαση στη διεύθυνση του δεύτερου δείκτη και με τον διπλό τελεστή ** έχουμε πρόσβαση στη μεταβλητή που δείχνει ο δεύτερος δείκτης Δήλωση Μεταβλητής (int) Δήλωση Δείκτη (ptr1) σε int Δήλωση Δείκτη (ptr) σε Δείκτη (που δείχνει σε int) O δείκτης ptr1 δείχνει στον i O δεύτερος δείκτης ptr δείχνει στον πρώτο δείκτη ptr1 **ptr = * (ptr1) = i 57 Παράδειγμα Ποια είναι η έξοδος του παρακάτω προγράμματος??? Έξοδος: 120 120 120 58 29

Δείκτες και Διδιάστατοι Πίνακες (Ι) Όπως και στους μονοδιάστατους πίνακες, έτσι και στους πολυδιάστατους, η κάθε διάσταση δηλώνεται μέσα σε αγκύλες [] Π.χ. με την εντολή: int arr[2][3]; δηλώνεται ένας διδιάστατος πίνακας, ο οποίος αποτελείται από 2 γραμμές και 3 στήλες (δηλ. συνολικά περιέχει 6 ακέραιες μεταβλητές) και σχηματικά απεικονίζεται όπως παρακάτω arr[0][0] arr[0][1] arr[0][2] arr[1][0] arr[1][1] arr[1][2] Τα στοιχεία του πίνακα αποθηκεύονται σε διαδοχικές θέσεις στη μνήμη ξεκινώντας από τα στοιχεία της 1η γραμμής, συνεχίζοντας με τα στοιχεία της 2ης γραμμής, κ.ο.κ. Άρα, η σειρά αποθήκευσης των στοιχείων του παραπάνω πίνακα arr στη μνήμη είναι: arr[0][0], arr[0][1], arr[0][2], arr[1][0], arr[1][1] και arr[1][2] 59 Δείκτες και Διδιάστατοι Πίνακες (ΙΙ) Η C για να χειριστεί με χρήση δεικτών έναν διδιάστατο πίνακα, έστω arr[ν][μ], θεωρεί ότι ο πίνακας arr αποτελείται από έναν πίνακα δεικτών N στοιχείων, arr[0], arr[1],..., arr[n-1], όπου καθένα από αυτά είναι δείκτης σε έναν πίνακα Μ στοιχείων Π.χ. με την εντολή: int arr[2][3]; η C θεωρεί ότι το arr[0] είναι ένας δείκτης προς έναν πίνακα 3 ακεραίων που περιέχει τα στοιχεία της πρώτης γραμμής, δηλαδή τα arr[0][0], arr[0][1] και arr[0][2] Συγκεκριμένα, το arr[0] είναι δείκτης στο πρώτο στοιχείο του πίνακα, δηλαδή στο arr[0][0] Άρα, η τιμή του *arr[0] είναι ίση με το arr[0][0] 60 30

Δείκτες και Διδιάστατοι Πίνακες (ΙΙΙ) Επίσης, σύμφωνα με την αριθμητική δεικτών: το arr[0]+1 είναι δείκτης στο δεύτερο στοιχείο του πίνακα, δηλαδή στο arr[0][1] το arr[0]+2 είναι δείκτης στο τρίτο στοιχείο του πίνακα, δηλαδή στο arr[0][2], κ.ο.κ.... συνεπώς, στη γενική περίπτωση ισχύει ότι το arr[0]+κ είναι δείκτης στο στοιχείο arr[0][κ] της πρώτης γραμμής του διδιάστατου πίνακα Δηλαδή, ισχύει ότι: το arr[0]+κ είναι ισοδύναμο με &arr[0][κ] η τιμή του *(arr[0]+κ) είναι ίση με arr[0][κ] 61 Δείκτες και Διδιάστατοι Πίνακες (ΙV) Αντίστοιχα, το arr[1] είναι ένας δείκτης προς έναν πίνακα 3 ακεραίων που περιέχει τα στοιχεία της δεύτερης γραμμής, δηλαδή τα arr[1][0], arr[1][1] και arr[1][2] Συγκεκριμένα: το arr[1] είναι δείκτης στο πρώτο στοιχείο του πίνακα, δηλαδή στο arr[1][0] Άρα, η τιμή του *arr[1] είναι ίση με το arr[1][0] Παρομοίως με πριν, ισχύει ότι το arr[1]+κ είναι δείκτης στο στοιχείο arr[1][κ] της δεύτερης γραμμής του διδιάστατου πίνακα Δηλαδή, ισχύει ότι: το arr[1]+κ είναι ισοδύναμο με &arr[1][κ] η τιμή του *(arr[1]+κ) είναι ίση με arr[1][κ] 62 31

Δείκτες και Διδιάστατοι Πίνακες (V) Γενικά, θεωρούμε ότι τα στοιχεία ενός πίνακα arr[n][m], είναι τα arr[0], arr[1],..., arr[n-1] τα οποία είναι δείκτες σε πίνακες που περιέχουν Μ στοιχεία της αντίστοιχης γραμμής Δηλαδή, το πρώτο στοιχείο του πίνακα arr[n][m] είναι το arr[0], το οποίο είναι δείκτης σε έναν πίνακα που περιέχει τα Μ στοιχεία της πρώτης γραμμής το δεύτερο στοιχείο του πίνακα arr[n][m] είναι το arr[1], το οποίο είναι δείκτης σε έναν πίνακα που περιέχει τα Μ στοιχεία της δεύτερης γραμμής... ενώ το τελευταίο στοιχείο είναι το arr[ν-1], το οποίο είναι δείκτης σε έναν πίνακα που περιέχει τα Μ στοιχεία της τελευταίας (της Ν-οστής) γραμμής 63 Παράδειγμα Τι κάνει το παρακάτω πρόγραμμα??? Εμφανίζει τις τιμές όλων των στοιχείων του πίνακα με χρήση δείκτη!!! 64 32

Χειρισμός Διδιάστατου Πίνακα με «δείκτη σε δείκτη» (Ι) Ένας εναλλακτικός τρόπος για να διαχειριστούμε έναν διδιάστατο πίνακα με χρήση δείκτη, είναι χρησιμοποιώντας το όνομα του πίνακα Θυμηθείτε ότι το όνομα ενός πίνακα χωρίς τις αγκύλες είναι ισοδύναμο με τη διεύθυνση του πρώτου στοιχείου του πίνακα Π.χ. αν θεωρήσουμε την παρακάτω δήλωση: int arr[2][3]; το όνομα του πίνακα arr είναι δείκτης στο πρώτο στοιχείο του πίνακα, δηλ. στο arr[0] Όμως, όπως είδαμε προηγουμένως, το πρώτο στοιχείο του πίνακα (το arr[0]) είναι με τη σειρά του δείκτης σε έναν πίνακα που περιέχει τα 3 στοιχεία της πρώτης γραμμής Συγκεκριμένα, το arr[0] είναι δείκτης στο πρώτο στοιχείο του πίνακα, δηλαδή στο arr[0][0] 65 Χειρισμός Διδιάστατου Πίνακα με «δείκτη σε δείκτη» (ΙΙ) Άρα, ισχύει ότι το arr είναι δείκτης στο arr[0] και το arr[0] είναι δείκτης στο arr[0][0] Επομένως, πώς μπορούμε να χειριστούμε το όνομα του πίνακα arr??? Η απάντηση είναι ότι μπορούμε να το χειριστούμε σαν δείκτη προς δείκτη Π.χ. αφού το arr είναι δείκτης σε έναν δείκτη που δείχνει στη διεύθυνση του στοιχείου arr[0][0], τότε το **arr είναι ίσο με την τιμή arr[0][0] Παρομοίως, το arr+1 είναι δείκτης στο arr[1] και το arr[1] είναι δείκτης που δείχνει στη διεύθυνση του στοιχείου arr[1][0] Άρα, το **(arr+1) είναι ίσο με την τιμή arr[1][0] Στη γενική περίπτωση, ισχύει ότι: το arr+κ είναι ισοδύναμο με &arr[κ] η τιμή του *(arr+κ) είναι ίση με arr[κ], δηλαδή ίση με &arr[κ][0] η τιμή του **(arr+κ) είναι ίση με arr[κ][0] 66 33

Παράδειγμα Τι κάνει το παρακάτω πρόγραμμα??? Εμφανίζει τις τιμές όλων των στοιχείων του πίνακα με χρήση του ονόματος του πίνακα ως «δείκτη σε δείκτη»!!! 67 Παρατηρήσεις Προφανώς, η διαχείριση των στοιχείων ενός διδιάστατου πίνακα με χρήση δεικτών (είτε απλού δείκτη είτε «δείκτη σε δείκτη») οδηγεί σε δυσνόητο και μη ευανάγνωστο κώδικα Για τον λόγο αυτό, προτείνουμε η διαχείριση των στοιχείων να γίνεται με τη χρήση των αγκυλών [][] και των αντιστοίχων θέσεων στον πίνακα 68 34

Δείκτης προς Συνάρτηση ΠΡΟΣΟΧΗ: Για να γίνει κατανοητή η συγκεκριμένη υποενότητα, θα πρέπει να έχει διδαχθεί η ενότητα των Συναρτήσεων Όταν εκτελείται ένα πρόγραμμα, ο κώδικας για κάθε συνάρτηση που περιέχει το πρόγραμμα φορτώνεται στη μνήμη αρχίζοντας σε μία συγκεκριμένη διεύθυνση Ένας δείκτης προς μία συνάρτηση δείχνει στη διεύθυνση μνήμης, στην οποία είναι αποθηκευμένος ο κώδικας της συνάρτησης Η γενική μορφή της δήλωσης ενός δείκτη προς μία συνάρτηση είναι: τύπος_επιστροφής (*όνομα_δείκτη) (τύπος_παραμ_1 όνομα_1, τύπος_παραμ_2 όνομα_2,..., τύπος_παραμ_ν όνομα_ν); Ο τύπος_επιστροφής καθορίζει τον τύπο δεδομένων που επιστρέφει η συνάρτηση στο πρόγραμμα που την κάλεσε Οι μεταβλητές όνομα_1, όνομα_2,..., όνομα_ν αποτελούν τις παραμέτρους (ορίσματα) της συνάρτησης Εάν η συνάρτηση δεν δέχεται παραμέτρους, τότε η λίστα παραμέτρων δηλώνεται ως void ή με κενές παρενθέσεις ( ) 69 Παραδείγματα δήλωσης Δείκτη προς Συνάρτηση 70 35

Παρατηρήσεις Το όνομα του δείκτη πρέπει να βρίσκεται ανάμεσα σε παρενθέσεις, γιατί ο τελεστής * έχει χαμηλότερη προτεραιότητα από τις παρενθέσεις που περιβάλλουν τη λίστα παραμέτρων της συνάρτησης Π.χ. αν γράψουμε: int *ptr(int a); αντί για int (*ptr)(int a); τότε δηλώνεται μία συνάρτηση με όνομα ptr, η οποία δέχεται μία ακέραια παράμετρο και επιστρέφει έναν δείκτη σε μία ακέραια μεταβλητή 71 Χρήση Δείκτη προς Συνάρτηση Η μόνη απαίτηση για να δείξει ένας δείκτης σε μία συνάρτηση είναι ο τύπος επιστροφής της συνάρτησης και η λίστα παραμέτρων της να είναι ίδια με τον τύπο επιστροφής και τη λίστα παραμέτρων της δήλωσης του δείκτη Παράδειγμα: 72 36

Παρατηρήσεις Η συνηθέστερη χρήση δείκτη σε συνάρτηση είναι για την επικοινωνία διαφορετικών τμημάτων ενός λογισμικού Δηλαδή, ένα πρόγραμμα «Α» μπορεί να επικοινωνήσει με κάποιο άλλο πρόγραμμα «Β» με τη χρήση ενός δείκτη σε κάποια συνάρτηση του προγράμματος «Β» 73 Πίνακας Δεικτών σε Συναρτήσεις Ένας πίνακας δεικτών σε συναρτήσεις είναι ένας πίνακας όπου κάθε στοιχείο του είναι δείκτης σε κάποια συνάρτηση Η δήλωσή του είναι παρόμοια με τη δήλωση ενός δείκτη σε συνάρτηση με τη διαφορά ότι αντί για ένας δείκτης δηλώνεται ένας πίνακας δεικτών Π.χ. η εντολή: void (*ptr[20])(int a); δηλώνει έναν πίνακα δεικτών με όνομα ptr, του οποίου τα στοιχεία είναι 20 δείκτες προς συναρτήσεις, οι οποίες δέχονται μία ακέραια παράμετρο και δεν επιστρέφουν τίποτα 74 37

Παράδειγμα Τι κάνει το παρακάτω πρόγραμμα??? (συνέχεια προγράμματος) 75 Παράδειγμα Το πρόγραμμα ανάλογα με την τιμή του i καλεί την αντίστοιχη συνάρτηση μέσω του δείκτη που δείχνει στη διεύθυνσή της. Η τιμή επιστροφής της συνάρτησης εμφανίζεται στην οθόνη. 76 38