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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ΤΕΜ-101 Εισαγωγή στους Η/Υ Εξεταστική Ιανουαρίου 2011 Θέματα Β

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

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

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

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

Εισαγωγή στην C. Μορφή Προγράµµατος σε γλώσσα C

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

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

Εισαγωγή στον δομημένο προγραμματισμό

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

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

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

Εισαγωγή στον Προγραµµατισµό. Διάλεξη 2 η : Βασικές Έννοιες της γλώσσας προγραµµατισµού C Χειµερινό Εξάµηνο 2011

Παρακάτω δίνεται o σκελετός προγράμματος σε γλώσσα C. Σχολιάστε κάθε γραμμή του κώδικα.

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

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

Κεφάλαιο 6: Συναρτήσεις IΙΙ Αρθρωτός Προγραμματισμός. (Διάλεξη 14) Παράδειγμα: Αλλαγή τιμής μεταβλητής μόνο τοπικά

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

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

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

Εισαγωγή στον Προγραµµατισµό «C»

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

ΕΠΛ 231 Δομές Δεδομένων και Αλγόριθμοι 4-1

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

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

Κεφάλαιο 6: Συναρτήσεις IΙΙ Αρθρωτός Προγραμματισμός. Δείκτες (Διάλεξη 14)

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

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

ΕΠΛ232 Προγραμματιστικές Τεχνικές και Εργαλεία Δείκτες και Συναρτήσεις (Κεφάλαιο 11, KNK-2ED)

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

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

Διδάσκων: Παναγιώτης Ανδρέου

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

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

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

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

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

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

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

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

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

Ασκήσεις σε Επαναληπτικούς Βρόχους και Συναρτήσεις. Επανάληψη για την ενδιάμεση εξέταση. (Διάλεξη 13)

ΕΡΓΑΣΤΗΡΙΟ 1 - ΣΗΜΕΙΩΣΕΙΣ

Διάλεξη 06: Συνδεδεμένες Λίστες & Εφαρμογές Στοιβών και Ουρών

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

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

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

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

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ Η/Υ Ακαδημαϊκό έτος ΤΕΤΡΑΔΙΟ ΕΡΓΑΣΤΗΡΙΟΥ #4

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

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

Επανάληψη για τις Τελικές εξετάσεις. (Διάλεξη 24) ΕΠΛ 032: ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΜΕΘΟΔΩΝ ΕΠΙΛΥΣΗΣ ΠΡΟΒΛΗΜΑΤΩΝ

3. Εκφράσεις και έλεγχος ροής

ΕΠΛ 231 οµές εδοµένων και Αλγόριθµοι Άννα Φιλίππου,

Εισαγωγή στον Προγραµµατισµό. Πανεπιστήµιο Θεσσαλίας Τµήµα Ηλεκτρολόγων Μηχανικών και Μηχανικών Η/Υ

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

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

Διάλεξη 3: Προγραμματισμός σε JAVA I. Διδάσκων: Παναγιώτης Ανδρέου

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

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

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

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

Κεφάλαιο 4: Συνθήκες Έλεγχου (if-else, switch) και Λογικοί τελεστές / παραστάσεις. (Διάλεξη 8)

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

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

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

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

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

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

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

Π. Σταθοπούλου ή Οµάδα Α (Φοιτητές µε µονό αριθµό Μητρώου ) ιδασκαλία : Παρασκευή 11πµ-13µµ ΗΛ7

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

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

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

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

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

Προγραμματισμό για ΗΜΥ

2.1. Εντολές Σχόλια Τύποι Δεδομένων

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

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

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

Κεφάλαιο 8.7. Πολυδιάστατοι Πίνακες (Διάλεξη 19)

Ανάπτυξη Μεγάλων Εφαρµογών στη Γλώσσα C (2)

Transcript:

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

Τι είναι ο δείκτης Ένας δείκτης είναι μια μεταβλητή που περιέχει μια διεύθυνση μνήμης. Θυμηθείτε πως η μνήμη μοιάζει με έναν μονοδιάστατο πίνακα. 0 4 8 12 16 20 24 28 32 36 40 Στο παράδειγμα που βλέπετε η θέση μνήμης 1024 περιέχει την τιμή 99. 1024 00000000 00000000 00000000 01100011 Χαροκόπειο Πανεπιστήμιο 2/59

Δήλωση Δείκτη σε C Το "*" χρησιμοποιείται για να δηλώσει δείκτη: int *p ; Η παραπάνω δήλωση δημιουργεί μια μεταβλητή τύπου δείκτη σε ακέραιο (pointer to int). Χαροκόπειο Πανεπιστήμιο 3/59

Δήλωση Δείκτη σε C Το "*" χρησιμοποιείται για να δηλώσει δείκτη: int *p ; Η παραπάνω δήλωση δημιουργεί μια μεταβλητή τύπου δείκτη σε ακέραιο (pointer to int). Το όνομα αυτής της μεταβλητής είναι p. Χαροκόπειο Πανεπιστήμιο 3/59

Δήλωση Δείκτη σε C Το "*" χρησιμοποιείται για να δηλώσει δείκτη: int *p ; Η παραπάνω δήλωση δημιουργεί μια μεταβλητή τύπου δείκτη σε ακέραιο (pointer to int). Το όνομα αυτής της μεταβλητής είναι p. Η τιμή της μεταβλητής είναι μία διεύθυνση μνήμης. Χαροκόπειο Πανεπιστήμιο 3/59

Ανάθεση Τιμής σε Δείκτη Όπως όλες τις άλλες μεταβλητές στην C πρέπει να αρχικοποιήσουμε έναν δείκτη. Για να βρούμε την διεύθυνση μνήμης μιας μεταβλητής χρησιμοποιούμε τον τελεστή &. int main ( ) { int a ; int *ptr ; a = 99; ptr = &a ; } return 0 ; Χαροκόπειο Πανεπιστήμιο 4/59

Ανάθεση Τιμής σε Δείκτη Για να βρούμε την διεύθυνση μνήμης μιας μεταβλητής χρησιμοποιούμε τον τελεστή &. int main ( ) { int a ; int *ptr ; a = 99; ptr = &a ; 0 4 8 12 16 1024 99 a } return 0 ; 1024 ptr Με αυτόν τον τρόπο ο δείκτης ptr "δείχνει" στην μεταβλητή a. Η τιμή της μεταβλητής ptr είναι η διεύθυνση μνήμης της μεταβλητής a. Χαροκόπειο Πανεπιστήμιο 5/59

Η Τιμή 0 και η Τιμή NULL Για να μην δείχνει ένας δείκτης κάπου πρέπει να του αναθέσουμε την τιμή 0. Η βιβλιοθήκη της C ορίζει μια σταθερά με όνομα NULL για να συμβολίσει το γεγονός πως ένας δείκτης δεν δείχνει πουθενά. int main ( ) { int *ptr = 0 ; / /... } return 0 ; ή #include < s t d i o. h> int main ( ) { int * ptr = NULL ; / /... } return 0 ; Χαροκόπειο Πανεπιστήμιο 6/59

Τελεστής Έμμεσης Αναφοράς Indirection/dereferencing operator Μπορούμε να ακολουθήσουμε ένα δείκτη με την χρήση του τελεστή έμμεσης αναφοράς, "*"; int main ( ) { int a ; int *ptr ; a = 99; ptr = &a ; 0 4 8 12 16 } printf ( "%d\n", *ptr ) ; return 0 ; 1024 99 a Η έκφραση *ptr μας δίνει την μεταβλητή στην θέση μνήμης που δείχνει ο δείκτης ptr. 2404 1024 ptr Στην προκειμένη περίπτωση είναι η μεταβλητή a. Χαροκόπειο Πανεπιστήμιο 7/59

Προτεραιότητα Τελεστών.1 παρενθέσεις: () [] expr++ expr Υπολογίζονται πρώτα, από τα αριστερά προς τα δεξιά. Εάν υπάρχουν ένθετες υπολογίζονται πρώτα οι εσωτερικές..2 μοναδιαίοι τελεστές: + ++expr expr! * & Υπολογίζονται από δεξιά προς τα αριστερά..3 πολλαπλασιασμός, διαίρεση και υπόλοιπο: * / % Υπολογίζονται δεύτερα από αριστερά προς τα δεξιά..4 πρόσθεση, αφαίρεση: + Εάν υπάρχουν πολλοί, υπολογίζονται από τα αριστερά προς τα δεξιά..5 Σχεσιακοί: < > <= >= Υπολογίζονται από τα αριστερά προς τα δεξιά..6 Ισότητας: ==!= Υπολογίζονται από τα αριστερά προς τα δεξιά..7 λογικό AND: && Από αριστερά προς τα δεξιά..8 λογικό OR: Από αριστερά προς τα δεξιά..9 εκχώρησης: = += = *= /= %= Από δεξιά προς τα αριστερά. Χαροκόπειο Πανεπιστήμιο 8/59

Τελεστής Έμμεσης Αναφοράς Indirection/dereferencing operator 1 int main ( ) { 2 int a, b ; 3 int * ptr_to_a, * ptr_to_b ; 4 5 a = 99; 6 ptr_to_a = &a ; 7 ptr_to_b = &b ; 8 9 * ptr_to_b = * ptr_t_a ; 10 printf ( "%d\n", *ptr_to_b ) ; 11 12 return 0 ; 13 } 0 4 8 12 16 1024 99 a 1028 2404 1024 1028 b ptr to a ptr to b Η γραμμή 10 είναι ουσιαστικά η γραμμή: 10 b = a ; ενώ η 11 είναι 12 printf ( "%d\n", b ) ; Χαροκόπειο Πανεπιστήμιο 9/59

Τελεστής Έμμεσης Αναφοράς Indirection/dereferencing operator 1 int main ( ) { 2 int a, b ; 3 int * ptr_to_a, * ptr_to_b ; 4 5 a = 99; 6 ptr_to_a = &a ; 7 ptr_to_b = &b ; 8 9 * ptr_to_b = * ptr_t_a ; 10 printf ( "%d\n", *ptr_to_b ) ; 11 12 return 0 ; 13 } 0 4 8 12 16 1024 99 a 1028 99 2404 1024 1028 b ptr to a ptr to b Η γραμμή 10 είναι ουσιαστικά η γραμμή: 10 b = a ; ενώ η 11 είναι 12 printf ( "%d\n", b ) ; Χαροκόπειο Πανεπιστήμιο 9/59

Δείκτες Άλλων Τύπων Στην γλώσσα C μπορούμε να έχουν δείκτες σε οποιαδήποτε μεταβλητή ανεξάρτητα από τον τύπο της. Πρέπει όμως να δηλώσουμε τον δείκτη ανάλογα. 1 #include < s t d i o. h> 2 3 int main ( ) { 4 double pi ; 5 double * ptr = &pi ; 6 7 * ptr = 3.14159265; 8 printf ( "%lf\n", pi ) ; 9 10 return 0 ; 11 } Αντίστοιχα και με τους υπόλοιπους τύπους. Χαροκόπειο Πανεπιστήμιο 10/59

Πολλοί Δείκτες, σε μια Μεταβλητή 1 int main ( ) { 2 int a ; 3 int *ptr1, *ptr2 ; 4 5 a = 99; 6 ptr1 = &a ; 7 ptr2 = &a ; 8 9 ( * ptr1 ) + + ; 10 ( * ptr2 ) + + ; 11 12 printf ( "%d\n", a ) ; 13 return 0 ; 14 } 0 4 8 12 16 1024 99 a 2404 2408 1024 1024 ptr1 ptr2 Η γραμμές 10 και 11 είναι ουσιαστικά η γραμμή: a++; Χαροκόπειο Πανεπιστήμιο 11/59

Πολλοί Δείκτες, σε μια Μεταβλητή 1 int main ( ) { 2 int a ; 3 int *ptr1, *ptr2 ; 4 5 a = 99; 6 ptr1 = &a ; 7 ptr2 = &a ; 8 9 ( * ptr1 ) + + ; 10 ( * ptr2 ) + + ; 11 12 printf ( "%d\n", a ) ; 13 return 0 ; 14 } 0 4 8 12 16 1024 101 a 2404 2408 1024 1024 ptr1 ptr2 Η γραμμές 10 και 11 είναι ουσιαστικά η γραμμή: a++; Το πρόγραμμα θα εκτυπώσει 101. Χαροκόπειο Πανεπιστήμιο 11/59

Εκτύπωση της Τιμή Ενός Δείκτη Η τιμή ενός δείκτη είναι μια διεύθυνση μνήμης. Για να τυπώσουμε την τιμή ενός δείκτη η printf() μας παρέχει την επιλογή %p. 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int a = 5 ; 5 int * ptr = &a ; 6 7 printf ( "address of a is %p\n", ptr ) ; 8 9 return 0 ; 10 } Στο σύστημα του ομιλητή το πρόγραμμα τυπώνει: address of a is 0x7fff5bc2d5cc Χαροκόπειο Πανεπιστήμιο 12/59

Συχνά Λάθη Δήλωση Πολλαπλών Δεικτών Προσοχή όταν ορίζετε πολλούς δείκτες στην ίδια γραμμή. int* ptr1, ptr2, ptr3 ; Το αστεράκι ανήκει ουσιαστικά στο όνομα και όχι στον τύπο. Η παραπάνω γραμμή ορίζει 1 δείκτη σε ακέραιο με όνομα ptr1 και δύο ακεραίους με ονόματα ptr2 και ptr3. Για να ορίσουμε 3 δείκτες σε ακέραιο πρέπει να γράψουμε: int *ptr1, *ptr2, *ptr3 ; Χαροκόπειο Πανεπιστήμιο 13/59

Συχνά Λάθη Δείκτης και το Αντικείμενο 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int a = 10, b = 20; 5 int *p1, *p2 ; 6 7 p1 = &a ; 8 p2 = &b ; 9 10 *p1 = *p2 ; 11 p1 = p2 ; 12 *p1 = *p2 ; 13 14 return 0 ; 15 } η γραμμή 11 είναι ισοδύναμη με a = b. η γραμμή 12 αναθέτει την διεύθυνση του b στον δείκτη p1. Οι δύο δείκτες δείχνουν στο b. η γραμμή 13 είναι ισοδύναμη με b = b. Χαροκόπειο Πανεπιστήμιο 14/59

Συχνά Λάθη Προτεραιότητα Τελεστών 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int x, *p ; 5 6 p = &x ; / * i n i t i a l i s e p o i n t e r * / 7 *p = 0 ; / * set x t o zero * / 8 printf ( "x is %d\n", x ) ; 9 printf ( "*p is %d\n", *p ) ; 10 11 *p += 1 ; / * increment what p p o i n t s t o * / 12 printf ( "x is %d\n", x ) ; 13 14 ( * p ) + + ; / * increment what p p o i n t s t o * / 15 printf ( "x is %d\n", x ) ; 16 17 return 0 ; 18 } Προσοχή η γραμμή 14 θέλει παρενθέσεις, αφού ο τελεστής postfix ++ έχει μεγαλύτερη προτεραιότητα από τον τελεστή *. Χαροκόπειο Πανεπιστήμιο 15/59

Κλήση Συνάρτησης Μέσω Αναφοράς Με την χρήση δεικτών μπορούμε να κάνουμε κλήση μέσω αναφοράς στην C. Θυμηθείτε πως στην C οι παράμετροι μιας συνάρτησης αντιγράφονται σε προσωρινές τοπικές μεταβλητές πριν κληθεί η συνάρτηση. Θα κάνουμε μια μικρή παρένθεση και θα εξηγήσουμε τον τρόπο λειτουργίας των κλήσεων συναρτήσεων. Χαροκόπειο Πανεπιστήμιο 16/59

Κλήση Συναρτήσεων Stack Frame Για να μπορούμε να υποστηρίζουμε κλήση συναρτήσεων ο μεταγλωττιστής παράγει κώδικα που χρησιμοποιεί την λεγόμενη στοίβα κλήσεων. Η στοίβα κλήσεων είναι υπεύθυνη για να αποθηκεύει διάφορες πληροφορίες όπως: την διεύθυνση επιστροφής μετά την συνάρτηση, τις παραμέτρους της συνάρτησης, τις τοπικές μεταβλητές της συνάρτησης, κ.τ.λ Χαροκόπειο Πανεπιστήμιο 17/59

Κλήση Συναρτήσεων Stack Frame Κάθε φορά που καλείται μια συνάρτηση προστίθεται στην κορυφή της στοίβας μια εγγραφή που περιέχει τις τοπικές μεταβλητές της συνάρτησης την διεύθυνση επιστροφής τις παραμέτρους της συνάρτησης Μόλις τελειώσει η εκτέλεση της συνάρτησης αφαιρείται η τελευταία εγγραφή, και άρα καταστρέφονται όλες οι τοπικές μεταβλητές και παράμετροι. Ο κώδικας δημιουργίας και καταστροφής των εγγραφών αυτών παράγεται από τον μεταγλωττιστή και προστίθεται σε κάθε σημείο του προγράμματος που γίνεται κλήση συνάρτησης. τοπικές μεταβλητές συνάρτησης διεύθυνση επιστροφής παράμετροι συνάρτησης τοπικές μεταβλητές συνάρτησης διεύθυνση επιστροφής παράμετροι συνάρτησης Χαροκόπειο Πανεπιστήμιο 18/59

Κλήση Συνάρτησης Μέσω Αναφοράς Για να υλοποιήσουμε κλήση μέσω αναφοράς στην C χρησιμοποιούμε δείκτες. Δίνουμε ως παράμετρο σε μια συνάρτηση ένα δείκτη στην μεταβλητή που θέλουμε να περάσουμε στην συνάρτηση. Μέσω του δείκτη αλλάζουμε την τιμή της μεταβλητής που θέλουμε Μόλις επιστρέψει η συνάρτηση η παράμετρος (δείκτης) θα καταστραφεί αλλά η μεταβλητή μας θα έχει αλλάξει κανονικά τιμή. Χαροκόπειο Πανεπιστήμιο 19/59

Κλήση Συνάρτησης Μέσω Αναφοράς 1 #include < s t d i o. h> 2 3 void increase ( int * x ) { 4 ( * x ) + + ; 5 } 6 7 int main ( ) { 8 int a = 1 ; 9 10 increase(&a ) ; 11 printf ( "%d\n", a ) ; 12 13 return 0 ; 14 } Η μεταβλητή x δείχνει στην μεταβλητή που θέλουμε να περάσουμε ως παράμετρο. Μέσα στην συνάρτηση αλλάζουμε την μεταβλητή μας χρησιμοποιώντας *x. Με το τέλος της συνάρτησης η τοπική μεταβλητή x θα καταστραφεί, αλλά η μεταβλητή a θα έχει αλλάξει τιμή. Το παραπάνω πρόγραμμα τυπώνει 2. Χαροκόπειο Πανεπιστήμιο 20/59

Κλήση Συνάρτησης Μέσω Αναφοράς 1 #include < s t d i o. h> 2 3 void swap ( int *a, int *b ) { 4 int tmp = * a ; 5 *a = *b ; 6 *b = tmp ; 7 } 8 9 int main ( ) { 10 int x = 1, 11 y = 2 ; 12 13 swap(&x, &y ) ; 14 15 printf ( "x = %d\n", x ) ; 16 printf ( "y = %d\n", y ) ; 17 18 return 0 ; 19 } Το πρόγραμμα τυπώνει x = 2 y = 1 Χαροκόπειο Πανεπιστήμιο 21/59

Δείκτες και const Θυμηθείτε πως με την δεσμευμένη λέξη const λέμε στον μεταγλωττιστή πως κάτι δεν πρέπει να αλλάξει. Επειδή όταν ασχολούμαστε με δείκτες έχουμε ουσιαστικά 2 αντικείμενα:.1 ένα δείκτη και.2 εκεί που δείχνει ο δείκτης η χρήση του const είναι λίγο πιο πολύπλοκη. Χαροκόπειο Πανεπιστήμιο 22/59

Δείκτες και const Υπάρχουν 3 χρήσεις:.1 const int * ptr ; Δείκτης σε σταθερό ακέραιο. Ο δείκτης μπορεί να αλλάξει τιμή, ο ακέραιος όχι..2 int * const ptr ; Σταθερός δείκτης σε ακέραιο. Ο δείκτης δεν μπορεί να αλλάξει τιμή, ο ακέραιος μπορεί..3 const int * const ptr ; Σταθερός δείκτης σε σταθερό ακέραιο. Ούτε ο δείκτης αλλά ούτε και ο ακέραιος μπορεί να αλλάξει τιμή. Είναι εύκολο να διακρίνεται τις περιπτώσεις κοιτώντας δεξιά και αριστερά του αστερίσκου για την δεσμευμένη λέξη const. Χαροκόπειο Πανεπιστήμιο 23/59

Δείκτες και const Παράδειγμα 1 #include < s t d i o. h> 2 3 int main ( ) { 4 const int y = 5 ; 5 const int x = 3 ; 6 7 const int * ptr = &y ; 8 10 9 ( * ptr ) + + ; / / NO! 11 ptr = &x ; / / ok 12 } Ο μεταγλωττιστής δεν μας επιτρέπει να γράψουμε την γραμμή 9. Χαροκόπειο Πανεπιστήμιο 24/59

Δείκτες και const Παράδειγμα 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int y = 5 ; 5 int x = 3 ; 6 7 int * const ptr = &y ; 8 10 9 ( * ptr ) + + ; / / ok 11 ptr = &x ; / / NO! 12 } Ο μεταγλωττιστής δεν μας επιτρέπει να γράψουμε την γραμμή 11. Χαροκόπειο Πανεπιστήμιο 25/59

Δείκτες και const Παράδειγμα 1 #include < s t d i o. h> 2 3 int main ( ) { 4 const int y = 5 ; 5 const int x = 3 ; 6 7 const int * const ptr = &y ; 8 10 9 ( * ptr ) + + ; / / NO! 11 ptr = &x ; / / NO! 12 } Ο μεταγλωττιστής δεν μας επιτρέπει να γράψουμε τις γραμμές 9 και 11. Χαροκόπειο Πανεπιστήμιο 26/59

Λάθη και casts Προσοχή με τα casts. 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int i ; 5 const int ci = 123; 6 7 const int *cpi ; / / p o i n t e r t o const 8 int *ncpi ; 9 10 cpi = &ci ; 11 ncpi = &i ; 12 13 cpi = ncpi ; / / allowed 14 15 / / t h i s needs a cast u s u a l l y BIG MISTAKE 16 ncpi = ( int * ) cpi ; 17 18 * ncpi = 0 ; / / UNDEFINED BEHAVIOR!! 19 } Χαροκόπειο Πανεπιστήμιο 27/59

Δείκτες και Πίνακες Οι πίνακες και οι δείκτες είναι πολύ στενά συνδεδεμένοι στην C. Για να δηλώσουμε ένα πίνακα ακεραίων μεγέθους 10 με όνομα a γράφουμε: int a [ 1 0 ] ; a : a[0] a[1] a[9] Χαροκόπειο Πανεπιστήμιο 28/59

Δείκτες και Πίνακες Εάν ο pa είναι ένας δείκτης σε ακέραιο int *pa ; τότε η ανάθεση pa = &a [ 0 ] ; βάζει τον pa να δείχνει στο μηδενικό στοιχείο του πίνακα a. pa : a : a[0] a[1] a[9] Χαροκόπειο Πανεπιστήμιο 29/59

Δείκτες και Πίνακες Από τον ορισμό, η τιμή μιας μεταβλητής ή έκφρασης τύπου πίνακα είναι η διεύθυνση του μηδενικού στοιχείου του πίνακα. Έτσι μετά την ανάθεση pa = &a [ 0 ] ; ο pa και ο a έχουν ακριβώς την ίδια τιμή. Επειδή το όνομα ενός πίνακα είναι συνώνυμο με την τοποθεσία του μηδενικού του στοιχείου, η τελευταία ανάθεση μπορεί να γραφεί και ως pa = a ; Χαροκόπειο Πανεπιστήμιο 30/59

Δείκτες και Πίνακες Επειδή το όνομα ενός πίνακα είναι συνώνυμο με την τοποθεσία του μηδενικού του στοιχείου, μπορούμε να κάνουμε και dereference. 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int a [ ] = { 9, 8, 7, 6, 5, 4, 3, 2, 1 } ; 5 6 printf ( "%d\n", *a ) ; 7 *a = 11; 8 printf ( "%d\n", a [ 0 ] ) ; 9 10 return 0 ; 11 } Το παραπάνω πρόγραμμα τυπώνει 9 11 Χαροκόπειο Πανεπιστήμιο 31/59

Δείκτες και Πίνακες Ένας δείκτης μπορεί να δείχνει σε μια μεταβλητή ενός πίνακα. #include < s t d i o. h> a ptr int main ( ) { int a [ ] = { 9, 8, 7, 6, 5 } ; int *ptr = &a [ 2 ] ; printf ( "%d\n", *ptr ) ; } return 0 ; Το παραπάνω πρόγραμμα τυπώνει 7 Χαροκόπειο Πανεπιστήμιο 32/59

Αριθμητική Δεικτών Έχοντας ένα δείκτη σε ένα στοιχείο ενός πίνακα, μπορούμε να κάνουμε αριθμητική δεικτών. #include < s t d i o. h> int main ( ) { int a [ ] = { 9, 8, 7, 6, 5 } ; int *ptr = &a [ 1 ] ; int *ptr1 = ptr + 2 ; printf ( "%d\n", *ptr ) ; printf ( "%d\n", *ptr1 ) ; a ptr ptr1 } return 0 ; Το παραπάνω πρόγραμμα τυπώνει 8 6 Χαροκόπειο Πανεπιστήμιο 33/59

Αριθμητική Δεικτών Στην αριθμητική δεικτών μπορούμε να προσθέσουμε ή να αφαιρέσουμε. Όταν γράφουμε p+1 όπου p είναι ένας δείκτης, το αποτέλεσμα είναι ένας δείκτης που δείχνει μια θέση μετά την θέση που δείχνει ο p. Πόσο μακρύτερα δείχνει ο p+1 από τον p εξαρτάται από τον τύπο δεδομένων που δείχνει ο p. Εαν ο p είναι ένας δείκτης σε ακεραίους τότε η θέση μνήμης p+1 θα είναι 4 bytes μετά την θέση p. Εαν όμως ο p δείχνει σε char τότε θα είναι μόλις 1 byte μετά. Χαροκόπειο Πανεπιστήμιο 34/59

Δείκτες και Πίνακες Όταν γράφουμε a[i] στην C, γίνεται η μετατροπή σε *(a+i). Οι δύο αυτές μορφές είναι ισοδύναμες. Χρησιμοποιώντας τον τελεστή & και στις δύο μορφές προκύπτει πως τα &a[i] a+i είναι επίσης ισοδύναμα. a+i είναι η διεύθυνση του i στοιχείου μετά το a. Παρόμοια έχοντας ένα δείκτη pa = &a[0] η έκφραση pa[2] είναι ισοδύναμη με *(pa + 2). Άρα μπορούμε να χρησιμοποιήσουμε ένα δείκτη με τον τελεστή []. Χαροκόπειο Πανεπιστήμιο 35/59

Δείκτες και Πίνακες Επειδή γράφοντας a[i] στην C, γίνεται η μετατροπή σε *(a+i), το ίδιο γίνεται και γράφοντας i[a]. a[i] *((a) + (i)) *((i) + (a)) i[a] (ορισμός) (αντιμεταθετικότητα πρόσθεσης) (ορισμός) Αυτό το γεγονός επιτρέπει να γράφουμε "περίεργο" κώδικα σε διαγωνισμούς "περίεργου" κώδικα C. Για παράδειγμα η έκφραση 5["abcdef" ] είναι απόλυτα σωστή και είναι ουσιαστικά ο χαρακτήρας 'f'. Χαροκόπειο Πανεπιστήμιο 36/59

Αριθμητική Δεικτών Αντιγραφή Συμβολοσειρών 1 void mystrcpy ( char * dest, const char * src ) { 2 char *dp = &dest [ 0 ], 3 *sp = &src [ 0 ] ; 4 5 while ( * sp!= '\0' ) 6 *dp++ = *sp++; 7 8 *dp = '\0' ; 9 } Η έκφραση *dp++ κάνει dereference τον δείκτη dp και μετά κάνει dp=dp+1. Για να αυξήσει την μεταβλητή που δείχνει ο dp πρέπει να γραφεί ως (*dp)++. Χαροκόπειο Πανεπιστήμιο 37/59

Αριθμητική Δεικτών Αντιγραφή Συμβολοσειρών Όταν κάνουμε αριθμητική δεικτών πρέπει να προσέχουμε να μην ξεφύγουμε εκτός πίνακα. 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int a [ ] = { 1, 2, 3, 4, 5 } ; 5 int *p = &a [ 2 ] ; 6 7 printf ( "%d\n", * ( p + 4 ) ) ; 8 9 return 0 ; 10 } Επειδή δεν γνωρίζουμε τι περιέχει και σε ποιον ανήκει η μνήμη εκτός του πίνακα, μπορεί να συμβεί οτιδήποτε. Χαροκόπειο Πανεπιστήμιο 38/59

Αριθμητική Δεικτών Μια μικρή εξαίρεση Όταν κάνουμε αριθμητική δεικτών μπορούμε να χρησιμοποιήσουμε για σύγκριση (όχι όμως και να κάνουμε dereference) την θέση που ακολουθεί αμέσως μετά το τέλος ενός πίνακα. 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int a [ ] = { 1, 2, 3, 4, 5 } ; 5 6 int *it = &a [ 0 ], 7 *end = it + 5 ; 8 9 while ( it < end ) { 10 printf ( "%d\n", *it + + ) ; 11 } 12 13 return 0 ; 14 } a it end Χαροκόπειο Πανεπιστήμιο 39/59

Αριθμητική Δεικτών Μια μικρή εξαίρεση 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int a [ ] = { 1, 2, 3, 4, 5 } ; 5 6 int *it = &a [ 0 ], 7 *end = it + 5 ; 8 9 while ( it < end ) { 10 printf ( "%d\n", *it + + ) ; 11 } 12 13 return 0 ; 14 } a it end Στον παραπάνω κώδικα που τυπώνει όλα τα στοιχεία ενός πίνακα, ο δείκτης end δείχνει αμέσως μετά το τέλος του πίνακα. Είναι επιτρεπτό να κάνουμε την σύγκριση it < end. Ο κώδικας είναι σωστός αρκεί να μην κάνουμε ποτέ *end. Χαροκόπειο Πανεπιστήμιο 39/59

Αριθμητική Δεικτών Μπορούμε να κάνουμε και αφαίρεση δεικτών. a 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int a [ ] = { 1, 2, 3, 4, 5 } ; 5 int *ptr1 = &a [ 0 ], 6 *ptr2 = &a [ 4 ] ; 7 8 printf ( "%d", ptr2 ptr1 ) ; 9 10 return 0 ; 11 } ptr1 ptr2 Τι εκτυπώνει ο παραπάνω κώδικας; Χαροκόπειο Πανεπιστήμιο 40/59

Δείκτες και Πίνακες Υπάρχει μια διαφορά μεταξύ του ονόματος ενός πίνακα και ενός δείκτη που πρέπει πάντα να θυμόμαστε. Ένας δείκτης είναι μια μεταβλητή και άρα εκφράσεις όπως pa = a ; ή pa++; είναι σωστές. Το όνομα ενός πίνακα όμως δεν είναι μεταβλητή και άρα οι αντίστοιχες a = pa ; ή a++; δεν επιτρέπονται. Χαροκόπειο Πανεπιστήμιο 41/59

Δείκτες, Πίνακες και Συναρτήσεις Όταν ένας πίνακας δίνεται σε μια συνάρτηση, ουσιαστικά δίνεται η θέση του πρώτου στοιχείου του πίνακα. Μέσα στην συνάρτηση, η παράμετρος είναι τοπική μεταβλητή, και άρα είναι ένας δείκτης. Οι παρακάτω δύο δηλώσεις είναι λοιπόν ισοδύναμες int strlen ( char s [ ] ) ; και int strlen ( char *s ) ; και καλό είναι να χρησιμοποιούμε τον δεύτερο τρόπο μιας και εξηγεί το γεγονός πως η παράμετρος s είναι δείκτης και όχι πίνακας. Χαροκόπειο Πανεπιστήμιο 42/59

Δείκτες, Πίνακες και Συναρτήσεις Είναι δυνατό να περάσουμε μέρος ενός πίνακα σε μια συνάρτηση, περνώντας ένα δείκτη στην αρχή του υποπίνακα. Για παράδειγμα εάν a είναι ένας πίνακας, τότε f(&a [ 2 ] ) και f ( a+2) περνάνε στην συνάρτηση την διεύθυνση του υποπίνακα που ξεκινά στο a[2]. Χαροκόπειο Πανεπιστήμιο 43/59

Δείκτες, Πίνακες και Συναρτήσεις Η συνάρτηση μπορεί να γραφεί ως f ( int arr [ ] ) {... } ή f ( int *arr ) {... } Η συνάρτηση f δεν διαφοροποιείται επειδή η παράμετρος αναφέρεται σε κομμάτι μεγαλύτερου πίνακα. Εάν κάποιος είναι σίγουρος πως τα στοιχεία υπάρχουν, μπορεί να χρησιμοποιήσει και αρνητικές διευθύνσεις όπως p[ 1] ή p[ 2]. Είναι φυσικά λάθος να βγεί κάποιος εκτός πίνακα. Χαροκόπειο Πανεπιστήμιο 44/59

Πίνακες Δεικτών Όπως μπορούμε να έχουμε πίνακες διαφόρων τύπων, με τον ίδιο τρόπο μπορούμε να έχουμε και πίνακες δεικτών. Η σύνταξη είναι λίγο πιο πολύπλοκη. Η παρακάτω εντολή δηλώνει ένα πίνακα με 10 δείκτες σε ακεραίους. int *a [ 1 0 ] ; Χαροκόπειο Πανεπιστήμιο 45/59

Πίνακες Δεικτών Παράδειγμα 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int i ; 5 int a [ 5 ] = { 0, 1, 2, 3, 4 } ; 6 int *ptr [ 5 ] ; 7 8 for ( i = 0 ; i < 5 ; i++) 9 ptr [ i ] = &a[4 i ] ; 10 11 for ( i = 0 ; i < 5 ; i++) 12 printf ( "%2d", *ptr [ i ] ) ; 13 14 return 0 ; 15 } a ptr Ο κώδικας τυπώνει 4 3 2 1 0 Χαροκόπειο Πανεπιστήμιο 46/59

Δείκτες σε Συναρτήσεις Η C εκτός από δείκτες σε τύπους μας επιτρέπει να έχουμε και δείκτες σε συναρτήσεις. Αυτό είναι επιτρεπτό αφού και οι συναρτήσεις είναι κάπου φορτωμένες στην μνήμη. Για να δηλώσουμε ένα δείκτη σε συνάρτηση, ο τύπος του δείκτη πρέπει να περιγράφει τις παραμέτρους και τον τύπο επιστροφής της συνάρτησης. int ( * ptr ) ( int, double ) ; Η παραπάνω εντολή δηλώνει ένα δείκτη σε συνάρτηση που πέρνει ως παραμέτρους έναν int και έναν double και επιστρέφει int. Το όνομα του δείκτη είναι ptr. Χαροκόπειο Πανεπιστήμιο 47/59

Δείκτες σε Συναρτήσεις Παρακάτω δηλώνουμε ένα δείκτη με όνομα ptr που μπορεί να δείχνει σε συνάρτηση που πέρνει μια παράμετρο τύπου int και επιστρέφει void. 1 #include < s t d i o. h> 2 3 void print ( int x ) { 4 printf ( "%d\n", x ) ; 5 } 6 7 int main ( ) { 8 void ( * ptr ) ( int ) ; 9 10 ptr = &print ; 11 12 return 0 ; 13 } Για να δείξει κάπου ο δείκτης χρησιμοποιούμε τον τελεστή διεύθυνσης &. Για παράδειγμα ptr = &print. Η C για ευκολία μας επιτρέπει να γράψουμε και ptr = print με το ίδιο αποτέλεσμα. Χαροκόπειο Πανεπιστήμιο 48/59

Δείκτες σε Συναρτήσεις 1 #include < s t d i o. h> 2 3 void print ( int x ) { 4 printf ( "%d\n", x ) ; 5 } 6 7 int main ( ) { 8 void ( * ptr ) ( int ) ; 9 10 ptr = &print ; 11 ( * ptr ) ( 5 ) ; 12 13 return 0 ; 14 } Για να χρησιμοποιήσουμε ένα δείκτη σε συνάρτηση τον κάνουμε dereference και δίνουμε παραμέτρους, π.χ (*ptr)(5). Η C για ευκολία μας επιτρέπει να γράψουμε και ptr(5) με το ίδιο αποτέλεσμα. Χαροκόπειο Πανεπιστήμιο 49/59

Δείκτες σε Συναρτήσεις 1 #include < s t d i o. h> 2 3 void foo ( int x ) { 4 printf ( "foo %d\n", x ) ; 5 } 6 7 void bar ( int y ) { 8 printf ( "bar %d\n", y ) ; 9 } 10 11 int main ( ) { 12 void ( * ptr ) ( int ) ; 13 14 ptr = &foo ; 15 ( * ptr ) ( 5 ) ; 16 17 ptr = &bar ; 18 ( * ptr ) ( 5 ) ; 19 20 return 0 ; 21 } Ο κώδικας καλεί μέσω ενός δείκτη τις 2 συναρτήσεις foo() και bar(). Χαροκόπειο Πανεπιστήμιο 50/59

Δείκτες σε Συναρτήσεις Παράμετροι Συναρτήσεων 1 #include < s t d i o. h> 2 3 void print ( int x, void ( * ptr ) ( int ) ) { 4 ( * ptr ) ( x ) ; 5 } 6 7 void foo ( int x ) { 8 printf ( "foo %d\n", x ) ; 9 } 10 11 void bar ( int y ) { 12 printf ( "bar %d\n", y ) ; 13 } 14 15 int main ( ) { 16 print ( 5, &foo ) ; 17 print ( 5, &bar ) ; 18 19 return 0 ; 20 } Μπορούμε να περάσουμε ένα δείκτη συνάρτησης ως παράμετρο σε άλλη συνάρτηση. Ο κώδικας καλεί πρώτα την foo() και μετά την bar(). Χαροκόπειο Πανεπιστήμιο 51/59

Επιστροφή Δείκτη Συνάρτησης Είναι λίγο πολύπλοκη η σύνταξη αλλά μπορούμε να γράψουμε το εξής: float ( * getfunction ( const char code ) ) ( float, float ) { / / code here } Που ορίζει μια συνάρτηση με όνομα getfunction η οποία πέρνει ως παράμετρο ένα χαρακτήρα τύπου const char, επιστρέφει ένα δείκτη σε συνάρτηση που έχει 2 float παραμέτρους και με την σειρά της επιστρέφει τύπο float. Χαροκόπειο Πανεπιστήμιο 52/59

Επιστροφή Δείκτη Συνάρτησης Παράδειγμα 1 #include < s t d i o. h> 2 3 float minus ( float f1, float f2 ) { return f1 f2 ; } 4 5 float plus ( float f1, float f2 ) { return f1+f2 ; } 6 7 float ( * getfunction ( const char code ) ) ( float, float ) 8 { 9 if ( code == '+' ) 10 return &plus ; 11 else if ( code == '-' ) 12 return &minus ; 13 return NULL ; 14 } 15 16 int main ( ) { 17 float f ; 18 f = ( * getfunction ( '+' ) ) ( 2. 0, 1. 0 ) ; 19 f = ( * getfunction ( '-' ) ) ( f, 1. 0 ) ; 20 printf ( "%f\n", f ) ; 21 22 return 0 ; 23 } Χαροκόπειο Πανεπιστήμιο 53/59

Πίνακες Δεικτών Συναρτήσεων Μπορούμε να έχουμε και πίνακες με δείκτες συναρτήσεων. Η σύνταξη είναι πάλι κάπως παράξενη. Παρακάτω φαίνεται πως μπορούμε να δηλώσουμε ένα πίνακα 10 θέσεων που κάθε θέση είναι ένας δείκτης σε μια συνάρτηση που επιστρέφει int και πέρνει 3 παραμέτρους float, char και char. int ( * funcarr [ 1 0 ] ) ( float, char, char ) ; Το όνομα του πίνακα είναι funcarr. Χαροκόπειο Πανεπιστήμιο 54/59

Πίνακες Δεικτών Συναρτήσεων 1 #include < s t d i o. h> 2 3 void foo1 ( int x ) { printf ( "foo1 %d\n", x ) ; } 4 void foo2 ( int x ) { printf ( "foo2 %d\n", x ) ; } 5 void foo3 ( int x ) { printf ( "foo3 %d\n", x ) ; } 6 void foo4 ( int x ) { printf ( "foo4 %d\n", x ) ; } 7 8 int main ( ) { 9 int i, j ; 10 void ( * farray [ 4 ] ) ( int ) = { NULL } ; 11 12 farray [ 0 ] = &foo1 ; 13 farray [ 1 ] = &foo2 ; 14 farray [ 2 ] = &foo3 ; 15 farray [ 3 ] = &foo4 ; 16 17 for ( i = 0 ; i < 100; i++) 18 for ( j = 0 ; j < 4 ; j++) 19 ( * farray [ j ] ) ( i ) ; 20 21 return 0 ; 22 } Χαροκόπειο Πανεπιστήμιο 55/59

Δείκτες σε void Στο παρακάτω πρόγραμμα 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int c ; 5 double * ptr ; 6 7 ptr = &c ; 8 9 return 0 ; 10 } ο μεταγλωττιστής μας προειδοποιεί πως test.c: In function main : test.c:8: warning: assignment from incompatible pointer type Χαροκόπειο Πανεπιστήμιο 56/59

Δείκτες σε void Η C μας παρέχει ένα δείκτη τύπου void που μπορεί να δείξει οπουδήποτε. 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int c ; 5 double k ; 6 void *ptr ; 7 8 ptr = &c ; 9 ptr = &k ; 10 11 return 0 ; 12 } Θα δούμε που χρησιμεύει σε επόμενες διαλέξεις. Χαροκόπειο Πανεπιστήμιο 57/59

Δείκτες σε Δείκτες Για να δηλώσουμε ένα δείκτη που να δείχνει σε μια μεταβλητή που είναι και αυτή δείκτης πρέπει να χρησιμοποιήσουμε την παρακάτω σύνταξη. int * * x ; Θα ήταν πιο ευδιάκριτο εαν γράφαμε int* *x για να καταλάβουμε πως ο x είναι ένας δείκτης που δείχνει σε ένα δείκτη ακεραίων. Χαροκόπειο Πανεπιστήμιο 58/59

Δείκτες σε Δείκτες 1 #include < s t d i o. h> 2 3 int main ( ) { 4 int a [ 5 ] = { 1, 2, 3, 4, 5 } ; 5 int *ptr1 = &a [ 2 ] ; 6 int * * ptr2 = &ptr1 ; 7 8 printf ( "%d\n", * * ptr2 ) ; 9 10 return 0 ; 11 } a ptr1 ptr2 Ο κώδικας τυπώνει 3 Χαροκόπειο Πανεπιστήμιο 59/59