Οι δομές (structs) στη γλώσσα C είναι ένας τρόπος οργάνωσης και αποθήκευσης διαφορετικών τύπων δεδομένων που σχετίζονται μεταξύ τους. Μια δομή αποτελείται από έναν ή περισσότερους υποσταθμούς (members), οι οποίοι μπορούν να είναι διάφορων τύπων, όπως ακέραιοι, χαρακτήρες, πραγματικοί αριθμοί ή ακόμη και άλλες δομές.
Οι δομές μας επιτρέπουν να δημιουργήσουμε προσαρμοσμένους τύπους δεδομένων, που συχνά αντιπροσωπεύουν ένα πιο σύνθετο αντικείμενο ή ένα σύνολο σχετικών πληροφοριών. Με τη χρήση δομών, μπορούμε να οργανώσουμε και να αποθηκεύσουμε δεδομένα με τρόπο που να είναι πιο δομημένος και ευέλικτος.
Για να ορίσουμε μια δομή, χρησιμοποιούμε τη δεσμευμένη λέξη “struct” ακολουθούμενη από το όνομα της δομής και την περιγραφή των υποσταθμών της μέσα σε ένα ζεύγος αγκυλών {}. Μετά τον ορισμό της δομής, μπορούμε να δημιουργήσουμε μεταβλητές αυτού του τύπου δηλώνοντας το όνομα της δομής ακολουθούμενο από το όνομα της μεταβλητής.
Η δομή ορίζεται ως εξής:
#include <stdio.h> struct student { char name[50]; int age; float gpa; }; int main() { struct student s1; // Δημιουργία μιας μεταβλητής τύπου struct student // Αποθήκευση δεδομένων στους υποσταθμούς της δομής strcpy(s1.name, "John Doe"); s1.age = 20; s1.gpa = 3.5; // Εκτύπωση των δεδομένων της δομής printf("Name: %s\n", s1.name); printf("Age: %d\n", s1.age); printf("GPA: %.2f\n", s1.gpa); return 0; }
Ο παραπάνω κώδικας δημιουργεί μια δομή με το όνομα “student”, η οποία περιέχει τρεις μεταβλητές υποσταθμούς: “name” (ένας χαρακτηριστικός πίνακας μήκους 50), “age” (ένας ακέραιος) και “gpa” (ένας πραγματικός αριθμός).
Στη συνέχεια, στη συνάρτηση main()
, δημιουργείται μια μεταβλητή με το όνομα s1
τύπου struct student
, η οποία αντιπροσωπεύει έναν φοιτητή. Χρησιμοποιώντας τον χειρισμό των μελών της δομής, αποθηκεύονται δεδομένα για το όνομα, την ηλικία και τον βαθμό GPA του φοιτητή.
Τέλος, μέσω των εντολών printf()
, τα δεδομένα της δομής εκτυπώνονται στην οθόνη, παρέχοντας πληροφορίες για το όνομα, την ηλικία και τον βαθμό GPA του φοιτητή.
Ο παραπάνω κώδικας είναι ένα παράδειγμα απλής χρήσης των δομών (structs) στη γλώσσα C, που επιτρέπουν τη δημιουργία προσαρμοσμένων τύπων δεδομένων για οργάνωση και αποθήκευση συσχετισμένων πληροφοριών.
Μπορούμε να αρχικοποιήσουμε μια δομή κατά τη δήλωσή της, χρησιμοποιώντας μια αρχικοποίηση δομής (structure initialization). Αυτό μας επιτρέπει να ορίσουμε αρχικές τιμές για τα μέλη της δομής κατά τη δήλωσή της.
Για παράδειγμα, με βάση τον προηγούμενο κώδικα με τη δομή “student”, μπορούμε να τη δηλώσουμε και να την αρχικοποιήσουμε ως εξής:
struct student { char name[50]; int age; float gpa; } s1 = { "John Doe", 20, 3.7 };
Στο παραπάνω παράδειγμα, δηλώνουμε τη δομή “student” και ταυτόχρονα αρχικοποιούμε το αντικείμενο s1
με τις αρχικές τιμές “John Doe” για το όνομα, 20 για την ηλικία και 3.7 για τον βαθμό GPA.
Με αυτόν τον τρόπο, μπορούμε να δημιουργήσουμε και να αρχικοποιήσουμε ένα αντικείμενο δομής ταυτόχρονα, χωρίς να χρειάζεται να γράψουμε επιπλέον κώδικα για την αρχικοποίηση των μελών της μετά τη δήλωσή της.
Αυτό θα δημιουργήσει ένα αντικείμενο της δομής “student” με τα μέλη του να έχουν τις αντίστοιχες τιμές.
[adinserter block=”2″]
Ναι, μπορούμε να δηλώσουμε έναν δείκτη προς μια δομή με την ίδια σύνταξη όπως οι δείκτες προς άλλους τύπους δεδομένων. Αυτό γίνεται με τη χρήση του τελεστή αναφοράς *
κατά τη δήλωση του δείκτη.
Για παράδειγμα, ας υποθέσουμε ότι έχουμε μια δομή με το όνομα “student”:
struct student { char name[50]; int age; float gpa; };
Για να δηλώσουμε έναν δείκτη προς αυτήν τη δομή, μπορούμε να γράψουμε:
struct student *ptr;
Ο δείκτης ptr
είναι τύπου struct student *
, δηλαδή είναι ένας δείκτης που μπορεί να δείχνει σε αντικείμενα τύπου struct student
. Αντίστοιχα με άλλους δείκτες, μπορούμε να χρησιμοποιήσουμε τον δείκτη ptr
για να προσπελάσουμε τα μέλη της δομής, χρησιμοποιώντας τον τελεστή αναφοράς ->
.
Για παράδειγμα, αν έχουμε ένα αντικείμενο δομής με το όνομα s
:
struct student s;
Μπορούμε να χρησιμοποιήσουμε τον δείκτη ptr
για να αναφερθούμε στο αντικείμενο s
και να προσπελάσουμε τα μέλη της δομής:
ptr = &s; ptr->age = 20;
Με την παραπάνω εκχώρηση, ο δείκτης ptr
δείχνει τώρα στο αντικείμενο s
και η γραμμή ptr->age = 20;
τίθεται η ηλικία του αντικειμένου s
σε 20.
Η δομή μπορεί επίσης να χρησιμοποιηθεί ως παράμετρος σε μια συνάρτηση ή να επιστραφεί από αυτήν:
struct student create_student(char name[], int age, float gpa) { struct student s; strcpy(s.name, name); s.age = age; s.gpa = gpa; return s; }
Στο παραπάνω παράδειγμα, δημιουργούμε μια νέα δομή “student” με τα μέλη που δίνονται σαν παράμετροι, τοποθετούμε αυτά τα μέλη στο αντικείμενο, και επιστρέφουμε τη δομή.
Μπορούμε να δημιουργήσουμε μια δομή (struct) χρησιμοποιώντας τη λέξη-κλειδί struct
και δηλώνοντας τα μέλη της εντός αγκυλών από πίσω:
struct student { char name[50]; int age; float gpa; };
Στο παραπάνω παράδειγμα δημιουργούμε μια δομή “student” η οποία έχει τρία μέλη: το όνομα (αλφαριθμητικό με μέγιστο μήκος 50 χαρακτήρες), την ηλικία (ακέραιος αριθμός) και το βαθμό (πραγματικός αριθμός).
Μπορούμε να δημιουργήσουμε μια νέα δομή “student” χρησιμοποιώντας την παραπάνω δήλωση ως εξής:
struct student s;
Αυτό θα δημιουργήσει ένα νέο αντικείμενο τύπου “student” με τα μέλη του να έχουν αυθαίρετες τιμές.
Για να έχουμε πρόσβαση στα μέλη της δομής, πρέπει να δημιουργήσουμε μια μεταβλητή τύπου δομής.
Χρησιμοποιούμε τη λέξη-κλειδί struct
μέσα στη συνάρτηση main()
και ακολουθούμε με το όνομα της δομής και την όνομασία της μεταβλητής τύπου δομής:
int main() { struct student s; s.age = 22; strcpy(s.name, "John"); s.gpa = 3.5; printf("Name: %s\n", s.name); printf("Age: %d\n", s.age); printf("GPA: %f\n", s.gpa); return 0; }
Στο παραπάνω παράδειγμα, έχουμε δημιουργήσει μια μεταβλητή “s” τύπου δομής “student” και έχουμε ορίσει τα μέλη της δομής μέσω αυτής της μεταβλητής. Έπειτα, τα εκτυπώνουμε με τη χρήση της συνάρτησης printf().
[adinserter block=”3″]
Για να έχουμε πρόσβαση στα μέλη μιας δομής, χρησιμοποιούμε τη σύνταξη με την τελεία (.).
Για παράδειγμα, για να ανατρέξουμε στο μέλος name της δομής “student” που ονομάζεται s, χρησιμοποιούμε την εντολή:
printf("Name: %s\n", s.name);
Ομοίως, για τα μέλη age και gpa, χρησιμοποιούμε την εντολή:
printf("Age: %d\n", s.age); printf("GPA: %f\n", s.gpa);
Τώρα μπορείτε εύκολα να δημιουργήσετε πολλαπλές μεταβλητές δομής με διαφορετικές τιμές, χρησιμοποιώντας μόνο μία δομή:
#include <stdio.h> struct student { int age; char name[50]; float gpa; }; int main() { struct student s1; // Δημιουργία μιας μεταβλητής τύπου struct student με όνομα s1 s1.age = 22; // Ανάθεση τιμής 22 στο πεδίο age του s1 strcpy(s1.name, "John"); // Αντιγραφή του κειμένου "John" στο πεδίο name του s1 s1.gpa = 3.5; // Ανάθεση τιμής 3.5 στο πεδίο gpa του s1 struct student s2; // Δημιουργία μιας μεταβλητής τύπου struct student με όνομα s2 s2.age = 20; // Ανάθεση τιμής 20 στο πεδίο age του s2 strcpy(s2.name, "Jane"); // Αντιγραφή του κειμένου "Jane" στο πεδίο name του s2 s2.gpa = 3.8; // Ανάθεση τιμής 3.8 στο πεδίο gpa του s2 printf("Student 1:\n"); printf("Name: %s\n", s1.name); // Εκτύπωση της τιμής του πεδίου name του s1 printf("Age: %d\n", s1.age); // Εκτύπωση της τιμής του πεδίου age του s1 printf("GPA: %f\n", s1.gpa); // Εκτύπωση της τιμής του πεδίου gpa του s1 printf("\nStudent 2:\n"); printf("Name: %s\n", s2.name); // Εκτύπωση της τιμής του πεδίου name του s2 printf("Age: %d\n", s2.age); // Εκτύπωση της τιμής του πεδίου age του s2 printf("GPA: %f\n", s2.gpa); // Εκτύπωση της τιμής του πεδίου gpa του s2 return 0; }
Ο παραπάνω κώδικας πραγματοποιεί τις ακόλουθες ενέργειες:
- Ορίζει μια δομή (struct) με όνομα “student” που περιέχει τρία πεδία: age (ηλικία), name (όνομα) και gpa (βαθμός).
- Στη συνάρτηση
main()
, δημιουργούνται δύο μεταβλητές τύπου “student”: s1 και s2. - Ανάθεση τιμών στα πεδία των μεταβλητών s1 και s2, μέσω του τελεστή “.” (dot operator) και του χρήση της συνάρτησης
strcpy()
για την αντιγραφή του ονόματος. - Εκτύπωση των πεδίων των μεταβλητών s1 και s2, χρησιμοποιώντας τη συνάρτηση
printf()
. Εμφανίζονται το όνομα, η ηλικία και ο βαθμός του κάθε φοιτητή. - Η συνάρτηση
main()
επιστρέφει την τιμή 0, υποδεικνύοντας ότι το πρόγραμμα ολοκληρώθηκε επιτυχώς.
Έτσι, ο κώδικας δημιουργεί και εμφανίζει πληροφορίες για δύο φοιτητές.
Να θυμάστε ότι οι συμβολοσειρές στο C είναι στην πραγματικότητα ένας πίνακας από χαρακτήρες, και δυστυχώς δεν μπορείτε να αναθέσετε μια τιμή σε έναν πίνακα με αυτόν τον τρόπο:
struct student { int age; char name[50]; float gpa; }; struct student s; s.name = "John"; // This is invalid!
Για να αντιγράψετε μια συμβολοσειρά σε ένα μέλος της δομής, πρέπει να χρησιμοποιήσετε τη συνάρτηση strcpy() από τη βιβλιοθήκη string.h:
struct student { int age; char name[50]; float gpa; }; struct student s; s.age = 22; strcpy(s.name, "John"); s.gpa = 3.5;
Στο παραπάνω παράδειγμα, αναθέτουμε τη συμβολοσειρά “John” στο μέλος name της δομής s χρησιμοποιώντας τη συνάρτηση strcpy().
Μπορείτε επίσης να αναθέσετε τιμές στα μέλη ενός αντικειμένου δομής κατά τη δήλωσή τους, σε μία μόνο γραμμή.
Απλά εισάγετε τις τιμές σε μια λίστα χωρισμένη με κόμματα μέσα σε αγκύλες {}. Να σημειώσουμε ότι με αυτήν την τεχνική δεν χρειάζεται να χρησιμοποιήσετε τη συνάρτηση strcpy() για συμβολοσειρές:
struct student { int age; char name[50]; float gpa; }; struct student s = {22, "John", 3.5};
Στο παραπάνω παράδειγμα, δηλώνουμε ένα αντικείμενο δομής s τύπου “student”, και αναθέτουμε τις τιμές 22, “John” και 3.5 στα μέλη age, name και gpa αντίστοιχα, χρησιμοποιώντας μια γραμμή κώδικα.
[adinserter block=”4″]
Μπορείτε επίσης να αντιγράψετε μια δομή σε μια άλλη.
Στο παρακάτω παράδειγμα, οι τιμές της s1 αντιγράφονται στην s2:
struct student { int age; char name[50]; float gpa; }; struct student s1 = {22, "John", 3.5}; struct student s2; s2 = s1;
Στο παραπάνω παράδειγμα, οι τιμές των μελών age, name και gpa της s1 αντιγράφονται στα αντίστοιχα μέλη της s2.
Αν θέλετε να αλλάξετε / τροποποιήσετε μια τιμή, μπορείτε να χρησιμοποιήσετε τη σύνταξη με την τελεία (.).
Και για να τροποποιήσετε μια τιμή συμβολοσειράς, η συνάρτηση strcpy() είναι και πάλι χρήσιμη:
struct student { int age; char name[50]; float gpa; }; struct student s = {22, "John", 3.5}; s.age = 23; strcpy(s.name, "Mary"); s.gpa = 4.0;
Στο παραπάνω παράδειγμα, αλλάζουμε την ηλικία του s από 22 σε 23, το όνομα από “John” σε “Mary”, και το gpa από 3.5 σε 4.0.
Η τροποποίηση τιμών είναι ιδιαίτερα χρήσιμη όταν αντιγράφετε τιμές δομών:
struct student { int age; char name[50]; float gpa; }; struct student s1 = {22, "John", 3.5}; struct student s2; s2 = s1; s2.age = 23; strcpy(s2.name, "Mary"); s2.gpa = 4.0;
Στο παραπάνω παράδειγμα, αντιγράφουμε τις τιμές των μελών της s1 στην s2 και, στη συνέχεια, τροποποιούμε τις τιμές της s2, χωρίς να επηρεάζουμε τις τιμές της s1.
Μια χρήσιμη εφαρμογή των δομών είναι να χρησιμοποιούνται για να αποθηκεύουν διαφορετικές πληροφορίες σχετικά με ένα συγκεκριμένο αντικείμενο.
Για παράδειγμα, μπορούμε να χρησιμοποιήσουμε μια δομή για να αποθηκεύουμε διαφορετικές πληροφορίες σχετικά με έναν επεξεργαστή (CPU):
struct cpu { char brand[20]; char model[20]; int cores; float frequency; }; struct cpu my_cpu = {"Intel", "i7", 8, 2.6};
Στο παραπάνω παράδειγμα, η δομή cpu περιέχει τέσσερα μέλη, τα οποία αντιπροσωπεύουν τον κατασκευαστή, το μοντέλο, τον αριθμό των πυρήνων και τη συχνότητα του επεξεργαστή.
Στη συνέχεια, δημιουργούμε μια μεταβλητή my_cpu τύπου cpu και εκχωρούμε τις τιμές των μελών της δομής σε αυτήν.