Λειτουργίες Δείκτες στον Προγραμματισμό Γ με Παραδείγματα

Οι δείκτες δίνουν μεγάλες δυνατότητες στις συναρτήσεις '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 100
m is 100, n is 25

Παράδειγμα δείκτες συναρτήσεων

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

  1. Δηλώνουμε τη συνάρτηση υπεύθυνη για την εναλλαγή των δύο τιμών μεταβλητών, η οποία παίρνει δύο ακέραιους δείκτες ως παραμέτρους και επιστρέφει οποιαδήποτε τιμή όταν καλείται.
  2. Στην κύρια συνάρτηση, δηλώνουμε και αρχικοποιούμε δύο ακέραιες μεταβλητές ('m' και 'n') και στη συνέχεια εκτυπώνουμε τις τιμές τους αντίστοιχα.
  3. Καλούμε τη συνάρτηση swap() περνώντας τη διεύθυνση των δύο μεταβλητών ως ορίσματα χρησιμοποιώντας το σύμβολο συμπλεκτικού. Μετά από αυτό, εκτυπώνουμε τις νέες ανταλλαγμένες τιμές των μεταβλητών.
  4. Εδώ ορίζουμε το περιεχόμενο της συνάρτησης swap() που παίρνει δύο διευθύνσεις ακέραιων μεταβλητών ως παραμέτρους και δηλώνουμε μια προσωρινή ακέραια μεταβλητή που χρησιμοποιείται ως τρίτο πλαίσιο αποθήκευσης για να αποθηκεύσουμε μία από τις μεταβλητές τιμής που θα τοποθετηθούν στη δεύτερη μεταβλητή.
  5. Αποθηκεύστε το περιεχόμενο της πρώτης μεταβλητής που επισημαίνεται με 'a' στην προσωρινή μεταβλητή.
  6. Αποθηκεύστε τη δεύτερη μεταβλητή που επισημαίνεται με b στην πρώτη μεταβλητή που επισημαίνεται με α.
  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 <stdio.h>
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);}

Παραγωγή:

1
2
3
4
5

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

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

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

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

Δείκτες συνάρτησης

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

return_type (*function_name)(arguments)

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

#include <stdio.h>
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");}

Παραγωγή:

Hi
Hi
Hi

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

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

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

Συστοιχία δεικτών συνάρτησης

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

#include <stdio.h>
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 48
Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2
624

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

Συστοιχία δεικτών συνάρτησης

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

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

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

Οι δείκτες κενού χρησιμοποιούνται κατά τις δηλώσεις συναρτήσεων. Χρησιμοποιούμε άδειες τύπου void * return για να επιστρέψουμε οποιονδήποτε τύπο. Αν υποθέσουμε ότι οι παράμετροί μας δεν αλλάζουν κατά το πέρασμα σε μια συνάρτηση, τη δηλώνουμε ως const.
Για παράδειγμα:

 void * cube (const void *);

Σκεφτείτε το ακόλουθο πρόγραμμα:

#include <stdio.h>
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) που υποδεικνύεται από τον δείκτη num, και καθώς είναι κενός δείκτης, πρέπει να πληκτρολογήσουμε cast σε έναν ακέραιο τύπο δεδομένων χρησιμοποιώντας έναν συγκεκριμένο δείκτη σημειογραφίας (* τύπος δεδομένων) και επιστρέφουμε την τιμή του κύβου.
  2. Δηλώνουμε τον τελεστή και τη μεταβλητή αποτέλεσμα. Επίσης, αρχικοποιούμε τον τελεστή μας με την τιμή "4".
  3. Καλούμε τη συνάρτηση κύβου περνώντας τη διεύθυνση του τελεστή και χειριζόμαστε την επιστρεφόμενη τιμή στη μεταβλητή αποτελέσματος

Οι δείκτες συνάρτησης ως επιχειρήματα

Ένας άλλος τρόπος για να εκμεταλλευτείτε έναν δείκτη συνάρτησης μεταβιβάζοντάς τον ως όρισμα σε μια άλλη συνάρτηση που μερικές φορές ονομάζεται "συνάρτηση επανάκλησης" επειδή η συνάρτηση λήψης "τον καλεί πίσω".
Στο αρχείο κεφαλίδας 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 (*compare (const void *, const void *) : δείκτης συνάρτησης που αποτελείται από δύο ορίσματα και επιστρέφει 0 όταν τα ορίσματα έχουν την ίδια τιμή, <0 όταν το arg1 προηγείται του arg2 και >0 όταν το arg1 έρχεται μετά το arg2.

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

#include <stdio.h>
#include <stdlib.h>
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(). Γ χειριστής.
  3. Καλούμε το qsort συνάρτηση και περάστε το όνομα, το μέγεθος, το πλάτος και τη συνάρτηση σύγκρισης του πίνακα που ορίστηκε προηγουμένως από τον χρήστη, προκειμένου να ταξινομηθεί ο πίνακας μας σε αύξουσα σειρά. Η σύγκριση θα γίνει λαμβάνοντας σε κάθε επανάληψη δύο στοιχεία πίνακα μέχρι να ταξινομηθεί ολόκληρος ο πίνακας.
  4. Εκτυπώνουμε τα στοιχεία του πίνακα για να είμαστε σίγουροι ότι ο πίνακας μας είναι σωστά ταξινομημένος επαναλαμβάνοντας ολόκληρο τον πίνακα χρησιμοποιώντας για βρόχο.