13. Η έννοια της δομής

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

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

struct student  {
    char name[50];
    int id;
    float average_grade;
};

Το ακόλουθο παράδειγμα ορίζει μια δομή με όνομα circle, που παριστάνει ένα κύκλο, με τρία πεδία, τις συντεταγμένες του κέντρου ενός κύκλου και την ακτίνα του:

struct circle {
   int x;
   int y;
   float radius;
};

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

Μεταβλητές της δομής circle μπορούν να δηλωθούν με προτάσεις της μορφής:

struct circle mycirc, pcirc;

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

struct circle {
    int x;
    int y;
    float radius;
} mycirc, pcirc;

Εδώ δηλώνονται πάλι στο τέλος του ορισμού της δομής οι δυο μεταβλητές δομής mycirc, pcirc.

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

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

mycirc.x=10;
mycirc.y=20;

αποθηκεύουν τους αριθμούς 10 και 20 στα πεδία (συνταγμένων) x και y της μεταβλητής δομής mycirc (όπως έχει οριστεί σε παράδειγμα της προηγούμενης ενότητας).

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

struct circle
{
      char title[10];
      int x;
      int y;
      float radius;
};
int main(void)
{
      struct circle c={“MYCIRCLE”, 15, 20, 2.56};
      . . . . .
}

Οι αρχικές τιμές παρατίθενται με τη σειρά μέσα σε άγκιστρα. Η πρώτη τιμή θα ανατεθεί στο πρώτο πεδίο, η δεύτερη στο δεύτερο κ.ο.κ. Πρέπει να δίδεται προσοχή ώστε ο τύπος των αρχικών τιμών να είναι ο ίδιος με τον τύπο των αντίστοιχων πεδίων της δομής.

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

struct coordinates
{
     int x;
     int y;
     int z;
} points[50];

Με την παραπάνω δήλωση δημιουργείται ένας πίνακας 50 θέσεων με όνομα pointes ο οποίος αποτελείται από 50 δομές τύπου coordinates.

Η πρόσβαση στα διαφορετικά στοιχεία – δομές που αποτελούν τον πίνακα, γίνεται όπως σε όλους τους πίνακες. Για παράδειγμα το points[4] αναφέρεται στην πέμπτη δομή του πίνακα. Ένα πεδίο δομής προσπελάζεται με τον τελεστή τελεία (.) όπως στις απλές μεταβλητές δομής. Έτσι το points[3].y αναφέρεται στο πεδίο y της τέταρτης δομής του πίνακα.

Στην C μπορούμε να μεταβιβάσουμε μια ολόκληρη δομή σε μια συνάρτηση. Αυτό μπορεί να γίνει εφόσον η αντίστοιχη παράμετρος της συνάρτησης έχει τον ίδιο τύπο της δομής με το όρισμα που της μεταβιβάζεται από την καλούσα συνάρτηση. Όταν κατά την κλίση μιας συνάρτησης δίνεται ως όρισμα μια μεταβλητή δομής, τότε οι τιμές όλων των πεδίων της δομής του ορίσματος αντιγράφονται στα αντίστοιχα πεδία της παραμέτρου της συνάρτησης. Στο ακόλουθο παράδειγμα η παράμετρος p της συνάρτησης func έχει τον ίδιο τύπο δομής με το όρισμα mypoint με το οποίο καλείται η συνάρτηση func().

#include <avr/io.h>
struct point
{
     char c;
      int x;
      int y;
};
void func(struct point p)
{
     PORTA=p.c;
     PORTB=p.x;
     PORTC=p.y
}
int main(void)
{
     DDRA=0xFF;
     DDRB=0xFF;
     DDRC=0xFF;
     struct point mypoint;
     mypoint.c=’C’;
     mypoint.x=5;
     mypoint.y=15;
     func(mypoint);
     while(1);
}

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

#include <avr/io.h>
struct point
{
      char c;
      int x;
      int y;
};
int main(void)
{
     struct point mypoint, *ptr;
     mypoint.c=’A’;
     mypoint.x=10;
     mypoint.y=20;
     ptr = &mypoint;
     . . . . . .
    while(1);
}

Με την πρόταση ptr = &mypoint ο δείκτης ptr παίρνει ως τιμή την διεύθυνση της μεταβλητής δομής mypoint, δηλαδή ο δείκτης ptr δείχνει στη μεταβλητή δομής mypoint. Με αυτό τον τρόπο μπορούμε να προσπελάζουμε τα πεδία της μεταβλητής δομής mypoint μέσω του δείκτη ptr.

Σημείωση: η διεύθυνση μιας μεταβλητής δομής είναι η διεύθυνση του πρώτου από τα byte που καταλαμβάνει η μεταβλητή. Η διεύθυνση αυτή αποδίδεται μέσω του τελεστή &.

Τα πεδία μιας μεταβλητής δομής προσπελάζονται με δείκτη ως εξής:
Α] Με χρήση του τελεστή αναφορά (*). Έτσι η παράσταση (*ptr).x αναφέρεται στο πεδίο x της μεταβλητής mypoint. Για παράδειγμα, η πρόταση (*ptr).y=20; καταχωρίζει την τιμή 20 στο πεδίο y της δομής στην οποία δείχνει ο δείκτης ptr. Οι παρενθέσεις είναι υποχρεωτικές διότι ο τελεστής τελείας (.) έχει μεγαλύτερη προτεραιότητα  από τον τελεστή αναφοράς (*).
Β] Με χρήση του τελεστή βέλους -> (παύλα και >). Η παράσταση (*ptr).x είναι ισοδύναμη με την ptr->x . Για παράδειγμα, η παράσταση ptr->c=’A’; καταχωρίζει τον χαρακτήρα Α στο πεδίο c της δομής στην οποία δείχνει ο δείκτης ptr.

Η αριθμητική δεικτών σε δομές ακολουθεί τη γενικότερη λογική της αριθμητικής δεικτών που ισχύει και στους άλλους τύπους δεδομένων. Έτσι η αύξηση ενός δείκτη (που δείχνει σε δεδομένα δομής) κατά 1 αυξάνει την τιμή του δείκτη τόσο όσο το μέγεθος του συγκεκριμένου τύπου δομής σε bytes.

Μια δομή μπορεί να περιέχει σαν μέλος ένα πίνακα οποιοδήποτε τύπου. Για παράδειγμα, στη δήλωση της δομής triangle που ακολουθεί, το μέλος points είναι ένας πίνακας δυο διαστάσεων 3Χ2 για την αποθήκευση των συντεταγμένων των τριών σημείων – κορυφών του τριγώνου.

struct triangle
{
    char name[15];
    float points[3][2];
} tr1;