τι περιέχει αυτό το κεφάλαιο...
Καλως ήρθατε στους δείκτες!
Για λόγους ευκολίας ένας δείκτης είναι ένα "βελάκι" που δείχνει κάπου. Συγκεκριμένα σε ένα κουτί και τι είναι αυτό; Μια διεύθυνση μνήμης! Οπότε συνοψίζοντας μπορούμε να βγάλουμε τον ακόλουθο ορισμό:
έγραψε:Άν ο x είναι δείκτης τότε δείχνει σε μια θέση μνήμης και ΔΕΝ είναι αυτή η θέση μνήμης.
Απο την στιγμή που οι δείκτες 'παίζουν' με διευθύνσεις μνήμης θα πρέπει να γνωρίζουμε τι γίνετε με την μνήμη του υπολογιστή μας. Οι μνήμες λοιπόν, δεν είναι τίποτα άλλο απο κουτάκια στα οποία μπορούμε να τους βάλουμε τιμές. Το κάθε κουτάκι, είναι μια θέση μνήμης και έχει μια διεύθυνση και τιμή. Η αρχική τιμή είναι null ή αλλιως κενή! Χρησιμοπιώντας ή όχι τους δείκτες, με την εντολή ανάθεσης γεμίζουμε αυτό το κουτάκι με κάποια τιμή!
Δημιουργία ενός δείκτη
Στην C αν κάτι είναι δείκτης θα δηλώνεται μαζί με ένα αστεράκι. Να θυμάστε πως αυτά τα δύο πάνε μαζί. Η δήλωση ενός δείκτη γίενται ως εξής:
- Κώδικας: Επιλογή όλων
όνοματύπου *ptrname;
- όπου, όνοματύπου μπορεί να είναι int, char, float κτλ. Όπως δηλαδή ορίζουμε μια κανονική μεταβλητή και
- ptrname το όνομα ενός δείκτη.
Αρχικοποίηση ενός δείκτη
Ωραία! Κάναμε το πρώτο βήμα και φτιάξαμε ένα δείκτη. Δεσμεύσαμε με άλλα λόγια ένα κουτάκι μνήμης! Τι υπάρχει όμως μέσα στο κουτάκι; Αυτή τη στιγμή τίποτα. Για να αρχικοποιήσουμε και να βάλουμε κάτι μέσα στο κουτί θα πρέπει να του εκχωρήσουμε κάποια τιμή.
Ο τελεστής &(ampersand) δείνει μια διεύθυνση. Ως αποτέλεσμα γράφοντας κάτι σαν,
- Κώδικας: Επιλογή όλων
δείκτης = &μεταβλητή;
έχουμε αρχικοποιήσει τον δείκτη μας και πλέον δεν είναι άχρηστος! Τώρα ο δείκτης δείχνει στο κουτάκι με όνομα το όνομα της μεταβλητής.
Παράδειγμα..
- Κώδικας: Επιλογή όλων
char *ch1, *ch2;
float *value, percent;
ch1 = "billys";
percent = 23;
...παραπάνω βλέπουμε, δύο δείκτες τύπου char, έναν δείκτη τύπου float και μια κανονική μεταβλητή τύπου float.
Χρήση δεικτών...
Τώρα, φαντάζομαι πως μπορείτε να δηλώσετε και να δώσετε αρχική τιμή σε δείκτες. Πως & πότε θα τους χρησιμοποιείτε; Όταν ο τελεστής * προηγείται απο το όνομα ενός δείκτη τότε, αναφέρεται στο όνομα της μεταβλητής στην οποία δείχνει ο δείκτης. Ας υποθέσουμε οτι έχουμε αρχικοποιήσει έναν δείκτη ως εξής:
- Κώδικας: Επιλογή όλων
p_rate = &rate; /* εκχωρεί την διευνση της rate στην p_rate */
Σύμφωνα με τα παραπάνω αν γράψουμε *όνομαδείκτη θα αναφερθούμε στην μεταβλητή. Συνεπωώς για να εκτυπώσουμε την μεταβληη rate, θα πρέπει μέσα σε ένα printf να γράψουμε το εξής:
- Κώδικας: Επιλογή όλων
printf("%d", rate);
το οποίο είναι το ίδιο με:
- Κώδικας: Επιλογή όλων
printf("%d", *rate);
Παράδειγμα(όσα είπαμε μέχρι τώρα)
- Κώδικας: Επιλογή όλων
int *int_ptr ;
int myInt = 35 ;
int_ptr = & myInt ;
...ας δούμε αναλυτικά τι γίνεται παραπάνω!
- Έχουμε κάνει ένα κουτάκι με όνομα my_ptr τύπου int. Τα περιεχόμενα αφού είναι δείκτης αθ είναι μια διευνση τύπου int.
- Ορίζουμε και αρχικοποιούμε μια ματεβλητή τύπου int ίση με 35.
- Εκχωρούμε την διεύθυνση της μεταβλητής στο κουτάκι με τον δείκτη.
έγραψε:Το int_ptr πριν απο το 3ο βήμα γυρνά σκουπίδια! Αυτό γιατί απλά έχουμε φτιάξει έναν δείκτη και δεν του έχουμε δώσει αρχική τιμή.
Μετα απο την 3η εντολή γυρνά την διεύθυνση που του δώσαμε!
Θα πρέπει να έχετε πάρει μια ιδέα για το τί είναι δείκτης στην C και πως μπορεί να χρησιμοποιηθεί! Προτείνω να κάνετε μια παύση εδώ και να γράψετε 4-5 παραδειγματάκια δικά σας να δείτε πως μπορείτε να τους χρησιμοποιήσουμε.
δείτε ένα παράδειγμα:
- Κώδικας: Επιλογή όλων
#include <stdio.h>
int main()
{
int x; /* A normal integer*/
int *p; /* A pointer to an integer ("*p" is an integer, so p
must be a pointer to an integer) */
p = &x; /* Read it, "assign the address of x to p" */
scanf( "%d", &x ); /* Put a value in x, we could also use p here */
printf( "%d\n", *p ); /* Note the use of the * to get the value */
getchar();
}
Δείκτες & Συναρτήσεις
Με την χρήση δεικτών μπορούμε να περάσουμε παραπάνω απο ένα όρισμα σε μια συνάρτηση. Όταν χρησιμοποιούμε δείκτες με άλλα λόγια είναι σαν να έχουμε δεσμεύσει κάποιο χωρο μνήμης μόνο. Απο εκεί και πέρα μπορούμε απλά (φανταστείτε με βελάκια) να δημιουργήσουμε κι άλλες μεταβλητές που όμως απλά θα δείχνουν στον αρχικό χώρο μνήμης! Έτσι μπορούμε σε μια συνάρτηση να περάσουμε πολλές μεταβλητές και να αλλάξουμε πολλα πραγματα. Αυτό δεν σημαίνει πως θα έχουμε πολλά return(). Ισχύει ακόμη και τώρα οτι σε μια συνάρτηση θα υπάρχει ένα μόνο return(η τουλάχιστον ένα θα ενεργοποιείται)! Απλά, περνώντας "με αναφορά" όπως λέγεται έναν δείκτη μπορούμε να κάνεουμε κάποιες αλλαγές και κάθε φορά που γίενται μια αλλαγή στη συνάρτηση θα γίνεται αυτόματα και στο κυρίως πρόγραμμα. Άρα, όταν θα αλλάζει κάτι στην συνάρτηση θα αλλάζει και στην
main()! Αυτός ο τρόπος είναι ΠΟΛΥ ΣΗΜΑΝΤΙΚΟΣ και χρησιμοποιείται πολλές φορές.
Ας υποθέσουμε οτι έχουμε ορίσει δυο δείκτες ακεραίου τύπου και μια κανονική μεταβλητή ακεραίου τύπου. Δηλαδή απο κομμάτι κώδικα έχουμε αυτό:
- Κώδικας: Επιλογή όλων
int *ptr_start; /* 1ος δείκτης */
int *ptr_end; /* 2ος δείκτης */
int val_simp; /* απλή μεταβλητή */
έχοντας την παρακάτω συνάρτηση που απλά προσθέτει ένα,
- Κώδικας: Επιλογή όλων
int func(int val_simp, int *ptr_end, int *ptr_start) {
val_simp++;
*ptr_end++;
*ptr_start++;
return val_simp;
}
μπορούμε να την καλέσουμε απο την main με τον παρακάτω τρόπο,
int main(){
int *ptr_start; /* 1ος δείκτης */
int *ptr_end; /* 2ος δείκτης */
int val_simp; /* απλή μεταβλητή */
int temp;
temp = func(val_simp, &ptr_end, &ptr_start)
return 0;
}
Με άλλα λόγια ο τρόπος που δουλεύουμε είναι:
- Στην κλήση συναρτήσεων δηλώνουμε ΜΟΝΟ τα ΟΝΟΜΑΤΑ των μεταβλητών.
- Στο πέρασμα των παραμέτρων, δηλώνουμε και τον τύπο τους!
Καλή συνέχεια...

.

