Δείκτες συναρτήσεων

Ένα εκτελέσιμο πρόγραμμα, όπως και τα δεδομένα του, καταλαμβάνει κάποιες 
θέσεις μνήμης. Βέβαια οι περιοχές των δεδομένων είναι συνήθως διαχωρισμένες 
από τις περιοχές των εκτελέσιμων προγραμμάτων έτσι ώστε να μην υπάρχουν 
περιπτώσεις ανάμιξης εντολών με δεδομένα. Παρ' όλα αυτά όμως η διεύθυνση 
μνήμης του σημείο εισόδου καθε εκτελέσιμου προγράμματος, δηλαδή η πρώτη 
εκετλέσιμη εντολή του, δεν παύει να είναι συνδεδεμένο με ένα όνομα, όπως και 
η διεύθυνση κάθε μεταβλητής. Έτσι, γιά παράδειγμα, η διεύθυνση του σημείου 
εισόδου του κυρίως προγράμματος είναι συνδεδμένο με τη λέξη κλειδί main. 
Επίσης το σημείο εισόδου κάθε συνάρτησης είναι συνδεδεμένο με το όνομα της 
συνάρτησης. Τι εννοούμε όταν λέμε συνδεδεμένο; Το όνομα μιάς συνάρτησης 
είναι ένας δείκτης που έχει τιμή τη διεύθνση της θέσης μνήμης του σημείου 
εισόδου της συνάρτησης. Ποιός δίνει αυτή τη τιμή; Ο μεταφραστής και ο 
συνδετής δίνουν τις σχετικές τιμές και το σύστημα εκτέλεσης (ο φορωτής) την 
απόλυτη διεύθυνση. Επομένως μπορούμε να χειριστούμε μιά συνάρτηση μέσω 
δεικτών όπως και μιά μεταβλητή. 

Το πρόγραμμα που είναι αποθηκευμένο στο αρχείο FUNCPNT.C δίνει ένα τέτοιο 
παράδειγμα. Το πρόγραμμα ξεκινά με τρείς δηλώσεις προτύπων συναρτήσεων, 
των print_stuff, print_message και print_message. Και οι τρείς συναρτήσεις 
δεν επιστρέφουν τιμή με return και δέχονται μιά πραγματική τυπική παράμετρο.

Οι λειτουργίες που εκτελούν οι τρείς συναρτήσεις είναι πολύ απλές, ουσιαστικά 
μιά εκτύπωση. Συγκεκριμένα η print_stuff εκτυπώνει ένα σταθερό μήνυμα ενώ 
αγνοεί τη παράμετρό της, ενώ οι print_message και print_message εμφανίζουν 
την τιμή της παραμέτρου τους με διαφορετικό συνοδευτικό μήνυμα η κάθε μία.

Το ενδιαφέρον βρίσκεται στη δήλωση του δείκτη συνάρτησης και τη χρήση του. 
Ας δούμε πρώτα τη δήλωση. Το όνομα του δείκτη είναι function_pointer και 
το γεγονός οτι είναι δείκτης γίνεται αντιληπτό από το σύμβολο * πριν το όνομα. 
Ακόμη δηλώνουμε οτι η συνάρτηση στην οποία δείχνει ο δείκτης δεν επιστρέφει 
τιμή με return και δέχεται πραγματική τυπική παράμετρο. Προσοχή στο γεγονός 
οτι οι παρενθέσεις γύρω από το όνομα είναι απαραίτητες. Αν, γιά παράδειγμα, 
γράφαμε

void *(function_pointer)(float); ή void *function_pointer(float);

ο μεταφραστής θα θεωρούσε οτι δηλώνουμε μιά ακόμη συνάρτηση.

Στην αρχή του κυρίως προγράμματος δηλώνονται και αρχικοποιούνται δύο 
πραγματικές μεταβλητές, η pi και η double. Η πρώτη κλήση συνάρτησης του 
προγράμματος είναι προφανής και συνηθισμένη: καλείται η συνάρτηση 
print_stuff με το όνομά της. Αμέσως μετά έχουμε μιά διαφορετική κλήση. Το 
όνομα print_stuff εκχωρείται στο δείκτη συνάρτησης function_pointer. 
Όπως είπαμε το όνομα print_stuff αντιστοιχεί σε μιά θέση μνήμης που κρατά 
τη διεύθυνση του σημείου εισόδου της συνάρτησης print_stuff. Επομένως μετά 
την εκχώρσηση η διεύθυνση αυτή θα έχει αντιγραφεί και στη θέση μνήμης με 
όνομα function_pointer. Άρα μπορούμε τώρα να καλέσουμε τη συνάρτηση 
print_stuff με δύο τρόπους: είτε με το όνομά της είτε με το όνομα του δείκτη, 
αφού και αφού και τα δύο ονόματα θα μας στείλουν στο ίδιο σημείο εισόδου. 
Αυτό φαίνεται από την πρόταση που ακολουθεί την εκχώρηση.

Γιά να είμαστε πιό ακριβείς θα πρέπει να πούμε οτι ο δείκτης μιάς συνάρτησης, 
όπως και το όνομά της, δεν κρατούν σαν πλήροφορία μόνο τη διεύθυνση του 
σημείου εισόδου αλλά και το λεγόμενο πρωτόκολλο επικοινωνίας που 
περιλαμβάνει τον αριθμό και τον τύπο των παραμέτρων, καθώς επίσης και τον 
τύπο της πιθανής επιστρεφόμενης τιμής. Γι' αυτό η δήλωση του δείκτη 
συνάρτησης είναι τόσο λεπτομερής.

Στις υπόλοιπες προτάσεις του κυρίως προγράμματος βλέπουμε οτι ο ίδιος 
δείκτης συνάρτησης μπορεί να τροποποιηθεί και να δείξει άλλες συναρτήσεις, 
αρκεί αυτές οι συναρτήσεις να έχουν το ίδιο πρωτόκολλο επικοινωνίας με το 
κυρίως πρόγραμμα. Το αποτέλεσμα δίνεται αμέσως.  

   This is the print stuff function.
   This is the print stuff function.
   The data to be listed is 6.283180
   The data to be listed is 13.000000
   The data to be printed is 3.141590
   The data to be printed is 3.141590

Περιεχόμενα Κεφαλαίου