Δείκτες συναρτήσεων στον προγραμματισμό C με παραδείγματα

Πίνακας περιεχομένων:

Anonim

Οι δείκτες δίνουν τεράστιες δυνατότητες σε συναρτήσεις «C», στις οποίες είμαστε περιορισμένοι για να επιστρέψουμε μία τιμή. Με τις παραμέτρους του δείκτη, οι λειτουργίες μας μπορούν πλέον να επεξεργάζονται πραγματικά δεδομένα και όχι ένα αντίγραφο δεδομένων.

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

Σε αυτό το σεμινάριο, θα μάθετε-

  • Παράδειγμα Δείκτες Λειτουργιών
  • Λειτουργεί με παραμέτρους συστοιχίας
  • Λειτουργίες που επιστρέφουν μια σειρά
  • Δείκτες λειτουργιών
  • Σειρά δεικτών λειτουργίας
  • Λειτουργίες με χρήση κενών δεικτών
  • Δείκτες λειτουργιών ως επιχειρήματα

Παράδειγμα Δείκτες Λειτουργιών

Για παράδειγμα, το επόμενο πρόγραμμα ανταλλάσσει δύο τιμές των δύο:

void swap (int *a, int *b);int main() {int m = 25;int n = 100;printf("m is %d, n is %d\n", m, n);swap(&m, &n);printf("m is %d, n is %d\n", m, n);return 0;}void swap (int *a, int *b) {int temp;temp = *a;*a = *b;*b = temp;}}

Παραγωγή:

m is 25, n is 100m is 100, n is 25

Το πρόγραμμα ανταλλάσσει τις πραγματικές τιμές μεταβλητών επειδή η συνάρτηση αποκτά πρόσβαση σε αυτές με διεύθυνση χρησιμοποιώντας δείκτες. Εδώ θα συζητήσουμε τη διαδικασία του προγράμματος:

  1. Δηλώνουμε τη συνάρτηση υπεύθυνη για την ανταλλαγή των δύο μεταβλητών τιμών, η οποία παίρνει δύο ακέραιους δείκτες ως παραμέτρους και επιστρέφει οποιαδήποτε τιμή όταν καλείται.
  2. Στην κύρια συνάρτηση, δηλώνουμε και αρχικοποιούμε δύο ακέραιες μεταβλητές ('m' και 'n') και στη συνέχεια εκτυπώνουμε τις τιμές τους αντίστοιχα.
  3. Καλούμε τη λειτουργία swap () μεταβιβάζοντας τη διεύθυνση των δύο μεταβλητών ως ορίσματα χρησιμοποιώντας το σύμβολο ampersand. Μετά από αυτό, εκτυπώνουμε τις νέες τιμές ανταλλαγής μεταβλητών.
  4. Εδώ ορίζουμε το περιεχόμενο της λειτουργίας swap () που παίρνει δύο ακέραιες διευθύνσεις μεταβλητών ως παραμέτρους και δηλώνουμε μια προσωρινή ακέραια μεταβλητή που χρησιμοποιείται ως τρίτο κουτί αποθήκευσης για να αποθηκεύσουμε μία από τις μεταβλητές τιμής που θα τοποθετηθούν στη δεύτερη μεταβλητή.
  5. Αποθηκεύστε το περιεχόμενο της πρώτης μεταβλητής που επισημαίνεται με «a» στην προσωρινή μεταβλητή.
  6. Αποθηκεύστε τη δεύτερη μεταβλητή που επισημαίνεται με b στην πρώτη μεταβλητή που επισημαίνεται με a.
  7. Ενημερώστε τη δεύτερη μεταβλητή (δείχνεται με β) με την τιμή της πρώτης μεταβλητής που αποθηκεύτηκε στην προσωρινή μεταβλητή

Λειτουργεί με παραμέτρους συστοιχίας

Στο C, δεν μπορούμε να περάσουμε έναν πίνακα από τιμή σε μια συνάρτηση Ενώ, ένα όνομα πίνακα είναι ένας δείκτης (διεύθυνση), οπότε απλώς μεταφέρουμε ένα όνομα πίνακα σε μια συνάρτηση που σημαίνει να μεταβιβάσουμε έναν δείκτη στον πίνακα.

Για παράδειγμα, θεωρούμε το ακόλουθο πρόγραμμα:

int add_array (int *a, int num_elements);int main() {int Tab[5] = {100, 220, 37, 16, 98};printf("Total summation is %d\n", add_array(Tab, 5));return 0;}int add_array (int *p, int size) {int total = 0;int k;for (k = 0; k < size; k++) {total += p[k]; /* it is equivalent to total +=*p ;p++; */}return (total);}

Παραγωγή:

 Total summation is 471

Εδώ, θα εξηγήσουμε τον κωδικό προγράμματος με τις λεπτομέρειες του

  1. Δηλώνουμε και ορίζουμε τη συνάρτηση add_array () που παίρνει μια διεύθυνση πίνακα (δείκτης) με τον αριθμό στοιχείων ως παραμέτρους και επιστρέφει τη συνολική συσσωρευμένη άθροιση αυτών των στοιχείων. Ο δείκτης χρησιμοποιείται για την επανάληψη των στοιχείων του πίνακα (χρησιμοποιώντας τη σημείωση p [k]) και συγκεντρώνουμε το άθροισμα σε μια τοπική μεταβλητή η οποία θα επιστραφεί μετά από επανάληψη ολόκληρου του πίνακα στοιχείων.
  2. Δηλώνουμε και αρχικοποιούμε έναν ακέραιο πίνακα με πέντε ακέραια στοιχεία. Εκτυπώνουμε το συνολικό άθροισμα περνώντας το όνομα του πίνακα (που λειτουργεί ως διεύθυνση) και το μέγεθος του πίνακα στο add_array () που ονομάζεται συνάρτηση ως ορίσματα.

Λειτουργίες που επιστρέφουν μια σειρά

Στο C, μπορούμε να επιστρέψουμε έναν δείκτη σε έναν πίνακα, όπως στο ακόλουθο πρόγραμμα:

#include int * build_array();int main() {int *a;a = build_array(); /* get first 5 even numbers */for (k = 0; k < 5; k++)printf("%d\n", a[k]);return 0;}int * build_array() {static int Tab[5]={1,2,3,4,5};return (Tab);}

Παραγωγή:

12345

Και εδώ, θα συζητήσουμε τις λεπτομέρειες του προγράμματος

  1. Ορίζουμε και δηλώνουμε μια συνάρτηση που επιστρέφει μια διεύθυνση πίνακα που περιέχει μια ακέραια τιμή και δεν λαμβάνουμε επιχειρήματα.
  2. Δηλώνουμε έναν ακέραιο δείκτη που λαμβάνει τον πλήρη πίνακα που έχει δημιουργηθεί μετά την κλήση της συνάρτησης και εκτυπώνουμε το περιεχόμενό της επαναλαμβάνοντας ολόκληρο τον πίνακα πέντε στοιχείων.

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

Δείκτες λειτουργιών

Όπως γνωρίζουμε εξ ορισμού ότι οι δείκτες δείχνουν μια διεύθυνση σε οποιαδήποτε θέση μνήμης, μπορούν επίσης να δείχνουν στην αρχή του εκτελέσιμου κώδικα ως συναρτήσεις στη μνήμη.

Ένας δείκτης προς συνάρτηση δηλώνεται με το *, η γενική δήλωση της δήλωσής της είναι:

return_type (*function_name)(arguments)

Πρέπει να θυμάστε ότι οι παρενθέσεις γύρω από το (* function_name) είναι σημαντικές επειδή χωρίς αυτές, ο μεταγλωττιστής θα πιστεύει ότι το function_name επιστρέφει ένα δείκτη του return_type.

Μετά τον ορισμό του δείκτη συνάρτησης, πρέπει να τον αντιστοιχίσουμε σε μια συνάρτηση. Για παράδειγμα, το επόμενο πρόγραμμα δηλώνει μια συνήθη συνάρτηση, ορίζει έναν δείκτη συνάρτησης, εκχωρεί τον δείκτη συνάρτησης στη συνήθη συνάρτηση και στη συνέχεια καλεί τη συνάρτηση μέσω του δείκτη:

#include void Hi_function (int times); /* function */int main() {void (*function_ptr)(int); /* function pointer Declaration */function_ptr = Hi_function; /* pointer assignment */function_ptr (3); /* function call */return 0;}void Hi_function (int times) {int k;for (k = 0; k < times; k++) printf("Hi\n");} 

Παραγωγή:

HiHiHi

  1. Ορίζουμε και δηλώνουμε μια τυπική συνάρτηση που εκτυπώνει ένα Hi κείμενο k φορές που υποδεικνύεται από τους χρόνους παραμέτρων όταν καλείται η συνάρτηση
  2. Ορίζουμε μια συνάρτηση δείκτη (με την ειδική δήλωσή της) που παίρνει μια ακέραια παράμετρο και δεν επιστρέφει τίποτα.
  3. Αρχικοποιούμε τη λειτουργία δείκτη μας με τη λειτουργία Hi_function που σημαίνει ότι ο δείκτης δείχνει τη λειτουργία Hi_function ().
  4. Αντί να καλεί την τυπική συνάρτηση πατώντας το όνομα της συνάρτησης με ορίσματα, καλούμε μόνο τη συνάρτηση δείκτη περνώντας τον αριθμό 3 ως ορίσματα και αυτό είναι!

Λάβετε υπόψη ότι το όνομα της συνάρτησης δείχνει τη διεύθυνση έναρξης του εκτελέσιμου κώδικα όπως ένα όνομα πίνακα που δείχνει το πρώτο του στοιχείο. Επομένως, οι οδηγίες όπως το function_ptr = & Hi_function και (* funptr) (3) είναι σωστές.

ΣΗΜΕΙΩΣΗ: Δεν είναι σημαντικό να εισαγάγετε τον τελεστή διευθύνσεων και τον χειριστή έμμεσης * κατά την εκχώρηση λειτουργίας και την κλήση λειτουργίας.

Σειρά δεικτών λειτουργίας

Μια σειρά από δείκτες λειτουργίας μπορεί να παίξει έναν διακόπτη ή έναν ρόλο δήλωσης if για τη λήψη απόφασης, όπως στο επόμενο πρόγραμμα:

#include int sum(int num1, int num2);int sub(int num1, int num2);int mult(int num1, int num2);int div(int num1, int num2);int main(){ int x, y, choice, result;int (*ope[4])(int, int);ope[0] = sum;ope[1] = sub;ope[2] = mult;ope[3] = div;printf("Enter two integer numbers: ");scanf("%d%d", &x, &y);printf("Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: ");scanf("%d", &choice);result = ope[choice](x, y);printf("%d", result);return 0;}int sum(int x, int y) {return(x + y);}int sub(int x, int y) {return(x - y);}int mult(int x, int y) {return(x * y);}int div(int x, int y) {if (y != 0) return (x / y); else return 0;}
Enter two integer numbers: 13 48Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2624

Εδώ, συζητάμε τις λεπτομέρειες του προγράμματος:

  1. Δηλώνουμε και ορίζουμε τέσσερις συναρτήσεις που λαμβάνουν δύο ακέραια ορίσματα και επιστρέφουν μια ακέραια τιμή. Αυτές οι συναρτήσεις προσθέτουν, αφαιρούν, πολλαπλασιάζουν και διαιρούν τα δύο ορίσματα σχετικά με το ποια συνάρτηση καλείται από τον χρήστη.
  2. Δηλώνουμε 4 ακέραιοι για να χειριστούμε τελεστές, τύπο λειτουργίας και αποτέλεσμα αντίστοιχα. Επίσης, δηλώνουμε έναν πίνακα τεσσάρων δεικτών λειτουργίας. Κάθε δείκτης συνάρτησης του στοιχείου πίνακα λαμβάνει δύο ακέραιους παραμέτρους και επιστρέφει μια ακέραια τιμή.
  3. Εκχωρούμε και αρχικοποιούμε κάθε στοιχείο πίνακα με τη συνάρτηση που έχει ήδη δηλωθεί. Για παράδειγμα, το τρίτο στοιχείο που είναι ο τρίτος δείκτης συνάρτησης θα δείχνει τη λειτουργία λειτουργίας πολλαπλασιασμού.
  4. Αναζητούμε τελεστές και τύπο λειτουργίας από τον χρήστη που πληκτρολογείται με το πληκτρολόγιο.
  5. Καλέσαμε το κατάλληλο στοιχείο πίνακα (δείκτης λειτουργίας) με ορίσματα και αποθηκεύουμε το αποτέλεσμα που δημιουργείται από την κατάλληλη συνάρτηση.

Η εντολή int (* ope [4]) (int, int); καθορίζει τη σειρά των δεικτών λειτουργίας. Κάθε στοιχείο πίνακα πρέπει να έχει τις ίδιες παραμέτρους και τύπο επιστροφής.

Το αποτέλεσμα της δήλωσης = ope [επιλογή] (x, y); εκτελεί την κατάλληλη συνάρτηση σύμφωνα με την επιλογή που έκανε ο χρήστης Οι δύο εισαγόμενοι ακέραιοι είναι τα ορίσματα που μεταβιβάζονται στη συνάρτηση.

Λειτουργίες με χρήση κενών δεικτών

Οι άδειοι δείκτες χρησιμοποιούνται κατά τις δηλώσεις λειτουργίας. Χρησιμοποιούμε άδειες τύπου επιστροφής * για την επιστροφή οποιουδήποτε τύπου. Εάν υποθέσουμε ότι οι παράμετροι μας δεν αλλάζουν κατά τη μετάβαση σε μια συνάρτηση, την δηλώνουμε ως const.

Για παράδειγμα:

 void * cube (const void *); 

Εξετάστε το ακόλουθο πρόγραμμα:

#include void* cube (const void* num);int main() {int x, cube_int;x = 4;cube_int = cube (&x);printf("%d cubed is %d\n", x, cube_int);return 0;}void* cube (const void *num) {int result;result = (*(int *)num) * (*(int *)num) * (*(int *)num);return result;}

Αποτέλεσμα:

 4 cubed is 64 

Εδώ, θα συζητήσουμε τις λεπτομέρειες του προγράμματος:

  1. Ορίζουμε και δηλώνουμε μια συνάρτηση που επιστρέφει μια ακέραια τιμή και παίρνει μια διεύθυνση αμετάβλητης μεταβλητής χωρίς συγκεκριμένο τύπο δεδομένων. Υπολογίζουμε την τιμή κύβου της μεταβλητής περιεχομένου (x) που υποδεικνύεται από τον δείκτη αριθμού και, καθώς είναι κενός δείκτης, πρέπει να τον πληκτρολογήσουμε μετάδοση σε έναν ακέραιο τύπο δεδομένων χρησιμοποιώντας έναν δείκτη συγκεκριμένης σημειογραφίας (* τύπος δεδομένων) και επιστρέφουμε η τιμή του κύβου.
  2. Δηλώνουμε τον τελεστή και τη μεταβλητή αποτελέσματος. Επίσης, αρχικοποιούμε τον τελεστή μας με την τιμή "4."
  3. Καλούμε τη συνάρτηση cube περνώντας τη διεύθυνση τελεστή και χειριζόμαστε την τιμή επιστροφής στη μεταβλητή αποτελέσματος

Δείκτες λειτουργιών ως επιχειρήματα

Ένας άλλος τρόπος για να εκμεταλλευτείτε έναν δείκτη συνάρτησης μεταβιβάζοντάς τον ως επιχείρημα σε μια άλλη συνάρτηση που καλείται μερικές φορές "λειτουργία επιστροφής κλήσης" επειδή η συνάρτηση λήψης "την καλεί πίσω."

Στο αρχείο κεφαλίδας stdlib.h, η συνάρτηση Quicksort "qsort ()" χρησιμοποιεί αυτήν την τεχνική που είναι ένας αλγόριθμος αφιερωμένος στην ταξινόμηση ενός πίνακα.

void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
  • void * base: κενός δείκτης στον πίνακα.
  • size_t num: Ο αριθμός στοιχείου πίνακα.
  • size_t πλάτος Το μέγεθος του στοιχείου.
  • int (* σύγκριση (const void *, const void *): δείκτης συνάρτησης που αποτελείται από δύο ορίσματα και επιστρέφει 0 όταν τα ορίσματα έχουν την ίδια τιμή, <0 όταν το arg1 έρχεται πριν από το arg2 και> 0 όταν το arg1 έρχεται μετά το arg2.

Το ακόλουθο πρόγραμμα ταξινομεί έναν ακέραιο πίνακα από μικρό σε μεγάλο αριθμό χρησιμοποιώντας τη συνάρτηση qsort ():

#include #include int compare (const void *, const void *);int main() {int arr[5] = {52, 14, 50, 48, 13};int num, width, i;num = sizeof(arr)/sizeof(arr[0]);width = sizeof(arr[0]);qsort((void *)arr, num, width, compare);for (i = 0; i < 5; i++)printf("%d ", arr[ i ]);return 0;}int compare (const void *elem1, const void *elem2) {if ((*(int *)elem1) == (*(int *)elem2)) return 0;else if ((*(int *)elem1) < (*(int *)elem2)) return -1;else return 1;}

Αποτέλεσμα:

 13 14 48 50 52 

Εδώ, θα συζητήσουμε τις λεπτομέρειες του προγράμματος:

  1. Ορίζουμε τη συνάρτηση σύγκρισης που αποτελείται από δύο ορίσματα και επιστρέφει 0 όταν τα ορίσματα έχουν την ίδια τιμή, <0 όταν το arg1 έρχεται πριν από το arg2 και> 0 όταν το arg1 έρχεται μετά το arg2. Οι παράμετροι είναι ένας τύπος κενού δείκτη που μεταδίδεται στον κατάλληλο τύπο δεδομένων πίνακα (ακέραιος αριθμός)
  2. Ορίζουμε και αρχικοποίηση έναν ακέραιο συστοιχία Το μέγεθος του πίνακα αποθηκεύεται στη num μεταβλητή και το μέγεθος του κάθε στοιχείου συστοιχίας αποθηκεύεται σε μεταβλητό πλάτος χρησιμοποιώντας sizeof () προκαθοριστεί εμπορευόμενος C.
  3. Καλούμε τη συνάρτηση qsort και μεταβιβάζουμε το όνομα του πίνακα, το μέγεθος, το πλάτος και τη συνάρτηση σύγκρισης που ορίστηκε προηγουμένως από τον χρήστη, προκειμένου να ταξινομήσουμε τον πίνακα μας σε αύξουσα σειρά. Η σύγκριση θα πραγματοποιηθεί λαμβάνοντας σε κάθε επανάληψη δύο στοιχεία πίνακα μέχρι ολόκληρου του πίνακα θα ταξινομηθεί.
  4. Εκτυπώνουμε τα στοιχεία του πίνακα για να είμαστε σίγουροι ότι ο πίνακας μας έχει ταξινομηθεί σωστά επαναλαμβάνοντας ολόκληρο τον πίνακα χρησιμοποιώντας το loop.