Δείκτες στην C

Δείκτες στην C

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

Σε αυτό το άρθρο θα εισαχθεί η έννοια των δεικτών (pointers) στην γλώσσα προγραμματισμού C και θα δοθούν παραδείγματα για την σωστή χρήση τους. Οι δείκτες είναι εδώ για να μας κάνουν την ζωή πιο εύκολη !

Ορισμός

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

Τι είναι όμως η διεύθυνση μνήμης;

Για να απαντήσουμε στο ερώτημα πρέπει εξετάσουμε τι γίνεται στον υπολογιστή όταν εκτελούμε ένα πρόγραμμα. Κατά την εκτέλεση του προγράμματος, οι εντολές και τα δεδομένα μεταφέρονται από την δευτερεύουσα μνήμη (σκληρός δίσκος, ssd) στην κύρια μνήμη (RAM). Η RAM για να μπορέσει να οργανώσει όλη την πληροφορία τεμαχίζεται σε κελιά όπου κάθε κελί έχει μία διεύθυνση μνήμης.

Οπότε, ένας δείκτης μπορεί να δείχνει (όπως λέγεται) σε κάποιο κελί της μνήμης κυρίως για την τροποποίηση του περιεχομένου του.

Ας δούμε ένα απλό παράδειγμα

int var = 5; 
int *ptr = &var; 

Η μεταβλητή var είναι μία ακέραια μεταβλητή στην οποία αποθηκεύεται η τιμή 5. Κατά τη δημιουργία της μεταβλητής var, δεσμεύεται χώρος στην κύρια μνήμη και επομένως υπάρχει κάποια διεύθυνση μνήμης για αυτόν τον χώρο (ώστε να γνωρίζουμε που είναι αποθηκευμένη η τιμή 5). Για να πάρουμε τη διεύθυνση μνήμης από τον χώρο αυτόν χρησιμοποιούμε το λογόγραμμα & (ampersand). Η μεταβλητή ptr από την άλλη είναι ένας δείκτης που γίνεται αντιληπτός από το αστέρι Κλέινι (kleene star). Έτσι, αυτός ο απλός κώδικας τοποθετεί στον δείκτη την διεύθυνση μνήμης της μεταβλητής var. ΟΚ, και ;

Κάνοντας αυτήν την εκχώρηση της διεύθυνσης στον δείκτη, μπορούμε να τροποποιήσουμε το περιεχόμενο της μεταβλητής var από τον δείκτη ptr. Δηλαδή ο παρακάτω κώδικας θα τυπώσει το 13 στην έξοδό του.

*ptr = 13;
printf("%d\n",*ptr); 

Σημαντικότητα Δεικτών – Παραδείγματα Δείκτες στην C

Μέχρι στιγμής από τον ορισμό δεν κατανοήσαμε την χρησιμότητα των δεικτών για τη γλώσσα. Αυτό προφανώς έγινε γιατί απλά δώσαμε ένα αρχικό παράδειγμα ορισμού των δεικτών. Παρακάτω παραθέτουμε συγκεκριμένα παραδείγματα τα οποία δεν θα ήταν εφικτό να επιλυθούν χωρίς δείκτες. Οι αλγόριθμοι που παραθέτουμε είναι μικρά πηγαίου κώδικα στην C και αποσκοπούν μόνο για την εξοικείωση του χρήστη με την έννοια των δεικτών

Τροποποίηση μεταβλητών από συναρτήσεις (Παράδειγμα 1 – Δείκτες στην C)

Ας υποθέσουμε ότι χρειαζόμαστε μία συνάρτηση που θα βρίσκει το μεγαλύτερο αριθμό από ένα σύνολο 10 θετικών ακέραιων αριθμών που δίνονται από το πληκτρολόγιο και θα τον επιστρέφει στην main. Ο κώδικας παρουσιάζεται παρακάτω:

int get_max(){
   int i,n,max=-1; 
   for (i=0;i<10;i++) {
       scanf("%d",&n);
       if (max < n) max = n;
   }
   return max;

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

void min_max(int *max,int *min){
   int i,n;
   *min = 999999999  // κάτι πολύ μεγάλο 
   *max = -1 
   for (i=0;i<10;i++) {
      scanf("%d",&n); 
      if (*max < n) *max = n; 
      if (*min > n) *min = n;
   }
}

int main(){
   int max,min;
   min_max(&max,&min); 
   printf("%d %d\n",max,min); 
   return 0;
}

Κατά την εκτέλεση της συνάρτησης αλλάζουν οι τιμές των μεταβλητών max και min που ορίστηκαν στην main. Αν δεν στέλναμε με αναφορά (όπως λέγεται) τις τιμές, τότε αντί να τροποποιούμε το περιεχόμενο των δύο μεταβλητών που επιθυμούμε, θα τροποποιούσαμε δύο τοπικές μεταβλητές που θα ορίζονταν στη συνάρτηση.

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

Πέρασμα πινάκων σε συναρτήσεις (Παράδειγμα 2 – Δείκτες στην C)

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

int pass_array(int a[],int n); 
int pass_array2(int *a,int n);
int main(){
   int a[10]; 
   pass_array(a,10);
   pass_array2(a,10);
   return 0;
}

Παρατηρήστε ότι στην main στέλνουμε τον πίνακα a χωρίς αγκύλες. Αυτό αντιστοιχεί στην διεύθυνση μνήμης του πίνακα a. Όλα τα στοιχεία του πίνακα μπορούν να βρεθούν από την μετατόπιση της διεύθυνσης μνήμης του πίνακα κατά k θέσεις. Για παράδειγμα, το a[0] είναι η τιμή που είναι αποθηκευμένη στη διεύθυνση μνήμης του πίνακα a κατά 0 θέσεις ή (a+0)*. Ομοίως για τα υπόλοιπα. Επομένως ορίζοντας την αρχή του πίνακα και το μέγεθός του μπορούμε να γνωρίζουμε όλα τα στοιχεία του πίνακα.

Χρήσιμοι Σύνδεσμοι

  1. The memory and memory addresses
  2. Παραδείγματα χρήσης δεικτών

Αφήστε μια απάντηση