Διάλεξη 4: Δομές Δεδομένων (Structures)

struct — Ομαδοποίηση δεδομένων σε έναν τύπο

4.1 Τι είναι η struct;

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

💡 Παράδειγμα από την καθημερινή ζωή

Ένας φοιτητής έχει: όνομα, αριθμό μητρώου και βαθμό. Αυτά τα τρία ανήκουν μαζί — περιγράφουν έναν φοιτητή.

Χωρίς struct θα χρειαζόμασταν 3 ξεχωριστές μεταβλητές για κάθε φοιτητή. Με struct τα βάζουμε σε μία.

Η struct (structure = δομή) μας επιτρέπει να ομαδοποιούμε μεταβλητές διαφορετικών τύπων κάτω από ένα κοινό όνομα.

4.2 Ορισμός Δομής

Ορίζουμε μια struct έξω από το main(), συνήθως στην αρχή του αρχείου:

struct Student { char name[50]; /* το όνομα του φοιτητή */ int am; /* αριθμός μητρώου */ float grade; /* βαθμός (0.0 - 10.0) */ };

📌 Σημαντικό

Ο ορισμός της struct δεν δεσμεύει μνήμη — απλώς λέει στον compiler «υπάρχει ένας τύπος που λέγεται Student και έχει αυτά τα τρία πεδία». Η μνήμη δεσμεύεται όταν δηλώσουμε μεταβλητή αυτού του τύπου.

🏗️ Οπτικά — Τι έχει η struct Student;

struct Student
char[50]
name
π.χ. "Νίκος Αθανασίου"
int
am
π.χ. 1042
float
grade
π.χ. 8.5

4.3 Δήλωση Μεταβλητής Δομής

Αφού ορίσουμε τη δομή, μπορούμε να δηλώσουμε μεταβλητές της:

struct Student s1; /* δηλώνουμε έναν φοιτητή */ struct Student s2, s3; /* δηλώνουμε δύο φοιτητές */

Τώρα οι s1, s2, s3 είναι μεταβλητές τύπου struct Student — η καθεμία έχει τα δικά της name, am, grade.

📘 Ολοκληρωμένο Παράδειγμα — Ορισμός & Δήλωση Μαζί

Ας δούμε ολόκληρη την εικόνα: πρώτα ορίζουμε τη δομή και μετά δηλώνουμε μεταβλητές αυτού του τύπου:

#include <stdio.h> /* Βήμα 1: Ορίζουμε τη δομή Student */ struct Student { char name[50]; /* το όνομα του φοιτητή */ int am; /* αριθμός μητρώου */ float grade; /* βαθμός (0.0 - 10.0) */ }; int main() { /* Βήμα 2: Δηλώνουμε μεταβλητές τύπου struct Student */ struct Student s1; /* πρώτος φοιτητής */ struct Student s2, s3; /* δεύτερος και τρίτος */ /* Τώρα οι s1, s2, s3 είναι έτοιμες — η καθεμία έχει τα δικά της name, am, grade */ return 0; }

📌 Τι συμβαίνει εδώ;

Στο Βήμα 1 λέμε στον compiler «υπάρχει ένας τύπος Student με 3 πεδία». Στο Βήμα 2 δεσμεύεται πραγματικά μνήμη — μία φορά για κάθε μεταβλητή. Δηλαδή οι s1, s2, s3 είναι τρία ξεχωριστά «κουτιά» στη μνήμη, το καθένα με χώρο για name, am και grade.

4.4 Πρόσβαση στα Πεδία — Τελεστής Τελείας .

Για να διαβάσουμε ή να γράψουμε ένα πεδίο μιας δομής χρησιμοποιούμε την τελεία (.):

s1.am = 1042; /* βάζουμε τιμή στο πεδίο am */ s1.grade = 8.5; /* βάζουμε τιμή στο πεδίο grade */ strcpy(s1.name, "Νίκος"); /* αντιγράφουμε string στο name */ printf("Φοιτητής: %s\n", s1.name); printf("ΑΜ: %d\n", s1.am); printf("Βαθμός: %.1f\n", s1.grade);

📌 Υπενθύμιση: Πώς λειτουργεί η strcpy;

Στη C δεν μπορούμε να βάλουμε κείμενο σε πίνακα χαρακτήρων με το =. Χρησιμοποιούμε τη strcpy από τη βιβλιοθήκη <string.h>:

#include <stdio.h> #include <string.h> int main() { char city[30]; /* δηλώνουμε πίνακα χαρακτήρων */ /* city = "Τρίπολη"; ΔΕΝ γίνεται! Σφάλμα! */ strcpy(city, "Τρίπολη"); /* αντιγράφει το "Τρίπολη" μέσα στον πίνακα city */ printf("Πόλη: %s\n", city); /* εμφανίζει: Πόλη: Τρίπολη */ return 0; }

📘 Πλήρες Παράδειγμα 1 — Αποθήκευση και Εμφάνιση Φοιτητή

#include <stdio.h> #include <string.h> /* για τη strcpy — αντιγράφει κείμενο σε πίνακα χαρακτήρων */ struct Student { char name[50]; int am; float grade; }; int main() { struct Student s1; /* δηλώνουμε έναν φοιτητή */ strcpy(s1.name, "Νίκος Αθανασίου"); s1.am = 1042; s1.grade = 8.5; printf("Όνομα : %s\n", s1.name); printf("ΑΜ : %d\n", s1.am); printf("Βαθμός : %.1f\n", s1.grade); return 0; }

👉 Εμφανίζει:

Όνομα : Νίκος Αθανασίου ΑΜ : 1042 Βαθμός : 8.5

4.5 typedef — Απλοποίηση του Ονόματος

Κάθε φορά που δηλώνουμε μεταβλητή πρέπει να γράφουμε struct Student. Αυτό είναι κουραστικό. Το typedef μας επιτρέπει να δώσουμε ένα ψευδώνυμο στον τύπο:

typedef struct { char name[50]; int am; float grade; } Student; /* τώρα το "Student" είναι ο τύπος */

Τώρα μπορούμε να γράφουμε απλά:

Student s1; /* αντί για: struct Student s1 */ Student s2, s3;

✅ Καλή πρακτική

Στα σύγχρονα προγράμματα C χρησιμοποιούμε σχεδόν πάντα typedef για τις δομές — κάνει τον κώδικα πιο καθαρό και εύκολο στην ανάγνωση.

📘 Σύγκριση: Χωρίς typedef vs Με typedef

Ας δούμε το ίδιο πρόγραμμα γραμμένο με δύο τρόπους, για να φανεί η διαφορά:

❌ Χωρίς typedef — γράφουμε struct Student παντού

#include <stdio.h> struct Student { char name[50]; int am; float grade; }; int main() { struct Student s1 = {"Νίκος", 1042, 8.5}; /* struct Student παντού */ struct Student s2 = {"Μαρία", 2031, 9.0}; /* κουραστικό... */ printf("%s: %.1f\n", s1.name, s1.grade); printf("%s: %.1f\n", s2.name, s2.grade); return 0; }

✅ Με typedef — γράφουμε μόνο Student

#include <stdio.h> typedef struct { char name[50]; int am; float grade; } Student; int main() { Student s1 = {"Νίκος", 1042, 8.5}; /* πιο καθαρό! */ Student s2 = {"Μαρία", 2031, 9.0}; /* πιο σύντομο! */ printf("%s: %.1f\n", s1.name, s1.grade); printf("%s: %.1f\n", s2.name, s2.grade); return 0; }

Και τα δύο προγράμματα κάνουν ακριβώς το ίδιο πράγμα — η μόνη διαφορά είναι ότι με typedef δεν χρειάζεται να γράφουμε τη λέξη struct κάθε φορά.

4.6 Αρχικοποίηση Δομής

Μπορούμε να δώσουμε αρχικές τιμές απευθείας κατά τη δήλωση, με αγκύλες { }:

Student s1 = {"Μαρία Δήμου", 2031, 9.0}; /* ^name ^am ^grade */ printf("%s βαθμός: %.1f\n", s1.name, s1.grade);

Εμφανίζει: Μαρία Δήμου βαθμός: 9.0

Χωρίς αρχικοποίηση — δίνουμε τιμές μετά τη δήλωση

Αν δεν θέλουμε να δώσουμε τιμές κατά τη δήλωση, μπορούμε να τις βάλουμε μία-μία μετά:

Student s2; // δήλωση χωρίς αρχικοποίηση strcpy(s2.name, "Κώστας Ανδρέου"); // βάζουμε τιμή στο name s2.am = 3045; // βάζουμε τιμή στο am s2.grade = 7.5; // βάζουμε τιμή στο grade printf("%s βαθμός: %.1f\n", s2.name, s2.grade); // %s εμφανίζει κείμενο (string), %.1f εμφανίζει δεκαδικό με 1 ψηφίο

Εμφανίζει: Κώστας Ανδρέου βαθμός: 7.5

⚠️ Προσοχή

Η αρχικοποίηση με { } γίνεται μόνο στη δήλωση. Αν δηλώσουμε πρώτα και θέλουμε να δώσουμε τιμές μετά, πρέπει να τις βάζουμε μία-μία σε κάθε πεδίο.

📘 Παράδειγμα 2 — Ανάγνωση Δομής από τον Χρήστη

#include <stdio.h> // βιβλιοθήκη για printf και scanf /* Ορίζουμε μια δομή Student */ typedef struct { char name[50]; // όνομα φοιτητή (μέχρι 49 χαρακτήρες + '\0') int am; // αριθμός μητρώου float grade; // βαθμός } Student; int main() { Student s; // δημιουργούμε μια μεταβλητή δομής τύπου Student printf("Δώσε όνομα: "); scanf("%s", s.name); // διαβάζουμε το όνομα του φοιτητή // δεν χρειάζεται & γιατί το name είναι πίνακας χαρακτήρων printf("Δώσε ΑΜ: "); scanf("%d", &s.am); // διαβάζουμε τον αριθμό μητρώου // χρησιμοποιούμε & γιατί είναι απλή μεταβλητή printf("Δώσε βαθμό: "); scanf("%f", &s.grade); // διαβάζουμε τον βαθμό του φοιτητή printf("\n--- Καρτέλα Φοιτητή ---\n"); printf("Όνομα : %s\n", s.name); // εκτύπωση ονόματος printf("ΑΜ : %d\n", s.am); // εκτύπωση αριθμού μητρώου printf("Βαθμός: %.1f\n", s.grade); // εκτύπωση βαθμού με 1 δεκαδικό return 0; // τέλος προγράμματος }

🔄 Μικρή Επανάληψη — Δήλωση και Ορισμός Συναρτήσεων

Πριν δούμε πώς περνάμε δομές σε συναρτήσεις, ας κάνουμε μια μικρή παρένθεση και ας θυμηθούμε πώς λειτουργούν οι συναρτήσεις στη C.

1️⃣ Συνάρτηση πριν από τη main

(Ορισμός Συνάρτησης – Function Definition before main)

#include <stdio.h> /* ΟΡΙΣΜΟΣ ΣΥΝΑΡΤΗΣΗΣ πριν από τη main Function Definition (before main) Η συνάρτηση δέχεται δύο αριθμούς (parameters) και επιστρέφει το άθροισμά τους */ int add(int a, int b) { return a + b; // επιστρέφει το αποτέλεσμα (return value) } int main() { int result; // ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΗΣ (Function Call) // περνάμε τα ορίσματα (arguments) 3 και 4 result = add(3, 4); // εκτύπωση αποτελέσματος printf("Αθροισμα = %d\n", result); return 0; }

📌 Σημείωση

Εδώ δεν χρειάζεται prototype, γιατί ο compiler έχει ήδη δει τον ορισμό της συνάρτησης (function definition) πριν από τη main.

2️⃣ Συνάρτηση μετά τη main

(Δήλωση Συνάρτησης – Function Prototype / Function Declaration)

#include <stdio.h> /* ΔΗΛΩΣΗ ΣΥΝΑΡΤΗΣΗΣ Function Prototype / Function Declaration ενημερώνει τον compiler ότι υπάρχει αυτή η συνάρτηση */ int add(int a, int b); int main() { int result; // ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΗΣ (Function Call) result = add(3, 4); printf("Αθροισμα = %d\n", result); return 0; } /* ΟΡΙΣΜΟΣ ΣΥΝΑΡΤΗΣΗΣ μετά τη main Function Definition (after main) */ int add(int a, int b) { return a + b; }

📌 Μικρό Λεξιλόγιο

Ελληνικά Αγγλικά
Ορισμός συνάρτησης Function Definition
Δήλωση συνάρτησης Function Prototype / Function Declaration
Κλήση συνάρτησης Function Call
Παράμετροι Parameters
Ορίσματα Arguments
Τιμή επιστροφής Return Value

Παράμετροι vs Ορίσματα — Ποια η διαφορά;

Παράμετροι (Parameters) είναι οι μεταβλητές που δηλώνονται στον ορισμό της συνάρτησης. Βρίσκονται μέσα στις παρενθέσεις όταν τη γράφουμε και λειτουργούν σαν τοπικές μεταβλητές.

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

#include <stdio.h> /* Ορισμός συνάρτησης (Function Definition) */ int add(int a, int b) { // a,b = parameters (παράμετροι) return a + b; } int main() { int result; result = add(3, 4); // 3,4 = arguments (ορίσματα) printf("%d\n", result); return 0; }

4.7 Δομή σε Συνάρτηση

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

📘 Παράδειγμα 3 — Εκτύπωση Δομής μέσω Συνάρτησης

#include <stdio.h> /* Ορισμός της δομής Student */ typedef struct { char name[50]; // όνομα φοιτητή int am; // αριθμός μητρώου float grade; // βαθμός } Student; /* Συνάρτηση που δέχεται μια δομή Student */ void print_student(Student s) { // εκτυπώνει τα στοιχεία του φοιτητή printf("Όνομα : %s | ΑΜ: %d | Βαθμός: %.1f\n", s.name, s.am, s.grade); } int main() { // δημιουργούμε και αρχικοποιούμε δύο φοιτητές Student s1 = {"Νίκος", 1042, 8.5}; Student s2 = {"Μαρία", 2031, 9.0}; // καλούμε τη συνάρτηση και περνάμε τη δομή ως όρισμα print_student(s1); // εκτυπώνει τον πρώτο φοιτητή print_student(s2); // εκτυπώνει τον δεύτερο φοιτητή return 0; }

👉 Εμφανίζει:

Όνομα : Νίκος | ΑΜ: 1042 | Βαθμός: 8.5 Όνομα : Μαρία | ΑΜ: 2031 | Βαθμός: 9.0

📘 Παράδειγμα 3β — Συνάρτηση που Επιστρέφει τον Καλύτερο Φοιτητή

#include <stdio.h> // βιβλιοθήκη για printf /* ===================================================== ΟΡΙΣΜΟΣ ΔΟΜΗΣ (Structure Definition) Δημιουργούμε έναν νέο τύπο δεδομένων που λέγεται Student ===================================================== */ typedef struct { char name[50]; // όνομα φοιτητή int am; // αριθμός μητρώου float grade; // βαθμός } Student; // νέο όνομα τύπου (typedef) /* ===================================================== ΟΡΙΣΜΟΣ ΣΥΝΑΡΤΗΣΗΣ Function Definition (before main) Η συνάρτηση δέχεται δύο φοιτητές και επιστρέφει αυτόν που έχει τον μεγαλύτερο βαθμό. ===================================================== */ Student best_student(Student a, Student b) { /* a και b = PARAMETERS (παράμετροι) Είναι οι μεταβλητές που δηλώνονται στη συνάρτηση */ if (a.grade >= b.grade) return a; // επιστρέφουμε ολόκληρη τη δομή a else return b; // επιστρέφουμε ολόκληρη τη δομή b } /* ===================================================== ΚΥΡΙΑ ΣΥΝΑΡΤΗΣΗ ΠΡΟΓΡΑΜΜΑΤΟΣ main function ===================================================== */ int main() { /* Δημιουργία και αρχικοποίηση δομών τύπου Student */ Student s1 = {"Νίκος", 1042, 8.5}; // πρώτος φοιτητής Student s2 = {"Μαρία", 2031, 9.0}; // δεύτερος φοιτητής /* ================================================= ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΗΣ Function Call ================================================= */ Student winner = best_student(s1, s2); /* s1 και s2 = ARGUMENTS (ορίσματα) Είναι οι πραγματικές τιμές που περνάμε στη συνάρτηση */ /* Το αποτέλεσμα που επιστρέφει η συνάρτηση αποθηκεύεται στη μεταβλητή winner *μεταβλητή δομής (structure variable) */ printf("Καλύτερος: %s με βαθμό %.1f\n", winner.name, winner.grade); return 0; }

👉 Εμφανίζει:

Καλύτερος: Μαρία με βαθμό 9.0

📌 Τι μάθαμε;

Στο Παράδειγμα 3 η συνάρτηση δέχεται μια δομή. Στο Παράδειγμα 3β η συνάρτηση επιστρέφει μια δομή. Μπορούμε να κάνουμε και τα δύο — η δομή συμπεριφέρεται σαν οποιοσδήποτε άλλος τύπος.

4.8 Πίνακας από Δομές (Array of Structures)

1️⃣ Υπενθύμιση: Μία δομή φοιτητή

Πρώτα ορίζουμε έναν τύπο δομής για έναν φοιτητή.

typedef struct { char name[50]; // όνομα φοιτητή int am; // αριθμός μητρώου float grade; // βαθμός } Student;

Με αυτό δημιουργούμε έναν νέο τύπο δεδομένων που λέγεται: Student

2️⃣ Μία μεταβλητή δομής

Αν θέλουμε έναν φοιτητή, γράφουμε:

Student s1;

και προσπελαύνουμε τα πεδία με τελεία .

s1.am = 1001; s1.grade = 7.5;

3️⃣ Πολλοί φοιτητές

Αν έχουμε πολλούς φοιτητές, π.χ. 30 φοιτητές, δεν είναι πρακτικό να γράφουμε:

Student s1; Student s2; Student s3; ... Student s30;

Για αυτό χρησιμοποιούμε πίνακα δομών.

4️⃣ Πίνακας από δομές

Student class[30];

Αυτό σημαίνει:

👉 Δημιουργούμε πίνακα 30 στοιχείων   👉 Κάθε στοιχείο είναι δομή τύπου Student

Δηλαδή:

θέση πίνακα φοιτητής
class[0]Student
class[1]Student
class[2]Student
......
class[29]Student

5️⃣ Πρόσβαση σε στοιχεία πίνακα δομών

Πρώτα επιλέγουμε τη θέση του πίνακα και μετά το πεδίο.

class[0].am = 1001; class[0].grade = 7.5;

Δηλαδή:

class[0] → πρώτος φοιτητής    .am → αριθμός μητρώου    .grade → βαθμός

📘 Παράδειγμα — Πίνακας Φοιτητών και Μέσος Όρος

#include <stdio.h> /* ΟΡΙΣΜΟΣ ΔΟΜΗΣ Structure Definition */ typedef struct { char name[50]; // όνομα φοιτητή int am; // αριθμός μητρώου float grade; // βαθμός } Student; #define N 4 /* αριθμός φοιτητών */ int main() { /* ΠΙΝΑΚΑΣ ΑΠΟ ΔΟΜΕΣ Array of structures */ Student students[N] = { {"Νίκος", 1001, 8.0}, {"Μαρία", 1002, 9.5}, {"Γιώργης", 1003, 6.0}, {"Ελένη", 1004, 7.5} }; float sum = 0; // άθροισμα βαθμών int i; /* ΔΙΑΤΡΕΧΟΥΜΕ ΤΟΝ ΠΙΝΑΚΑ Traverse the array */ for (i = 0; i < N; i++) { /* students[i] → i-οστός φοιτητής */ printf("%s: %.1f\n", students[i].name, students[i].grade); /* προσθέτουμε τον βαθμό στο άθροισμα */ sum += students[i].grade; } /* ΥΠΟΛΟΓΙΣΜΟΣ ΜΕΣΟΥ ΟΡΟΥ */ printf("\nΜέσος όρος τάξης: %.2f\n", sum / N); return 0; }

🔎 Πώς εκτελείται το πρόγραμμα

1️⃣ Δημιουργείται ο πίνακας

students[0] students[1] students[2] students[3]

Κάθε στοιχείο είναι δομή Student.

2️⃣ Το for διατρέχει τον πίνακα

i = 0 i = 1 i = 2 i = 3

3️⃣ Σε κάθε επανάληψη προσπελαύνουμε:

students[i].name students[i].grade

και προσθέτουμε τον βαθμό στο sum.

4️⃣ Τέλος υπολογίζεται ο μέσος όρος

sum / N

📌 Τι εμφανίζει:

Νίκος: 8.0 Μαρία: 9.5 Γιώργης: 6.0 Ελένη: 7.5 Μέσος όρος τάξης: 7.75

✅ Μικρό tip για να το θυμάσαι:

students[i].grade │ │ │ └─ πεδίο της δομής └────────── στοιχείο πίνακα

4.9 Pointer σε Δομή — Τελεστής ->

Μπορούμε να έχουμε pointer που δείχνει σε μια δομή. Τότε για να προσπελάσουμε τα πεδία χρησιμοποιούμε τον τελεστή βέλους -> αντί για τελεία.

#include <stdio.h> /* ΟΡΙΣΜΟΣ ΔΟΜΗΣ (Structure Definition) */ typedef struct { char name[50]; // όνομα φοιτητή int am; // αριθμός μητρώου float grade; // βαθμός } Student; int main() { /* ===================================== ΔΗΜΙΟΥΡΓΙΑ ΜΕΤΑΒΛΗΤΗΣ ΔΟΜΗΣ ===================================== */ Student s1 = {"Νίκος", 1042, 8.5}; /* s1 είναι μεταβλητή δομής τύπου Student και περιέχει 3 πεδία: s1.name s1.am s1.grade */ /* ===================================== ΔΗΜΙΟΥΡΓΙΑ ΔΕΙΚΤΗ ΣΕ ΔΟΜΗ ===================================== */ Student *ptr = &s1; /* ptr είναι POINTER σε δομή Student &s1 -> διεύθυνση μνήμης της s1 Άρα: ptr δείχνει (points) στη μεταβλητή s1 */ /* ===================================== ΠΡΟΣΠΕΛΑΣΗ ΠΕΔΙΟΥ ΜΕ ΤΕΛΕΙΑ (.) ===================================== */ printf("%s\n", s1.name); /* χρησιμοποιούμε τελεία (.) όταν έχουμε την ίδια τη δομή s1.name │ └── πρόσβαση στο πεδίο name */ /* ===================================== ΠΡΟΣΠΕΛΑΣΗ ΠΕΔΙΟΥ ΜΕ POINTER ===================================== */ printf("%s\n", ptr->name); /* ptr->name σημαίνει: πήγαινε στη δομή που δείχνει ο ptr και πάρε το πεδίο name */ /* ===================================== ΙΣΟΔΥΝΑΜΗ ΜΟΡΦΗ ===================================== */ printf("%s\n", (*ptr).name); /* εξήγηση: *ptr -> η δομή στην οποία δείχνει ο ptr (*ptr).name -> το πεδίο name αυτής της δομής Αυτό είναι ΑΚΡΙΒΩΣ το ίδιο με: ptr->name */ /* άλλο παράδειγμα πρόσβασης */ printf("%d\n", ptr->am); /* παίρνουμε τον αριθμό μητρώου της δομής που δείχνει ο ptr */ return 0; }

🔑 Κανόνας απλός

Αν έχεις μεταβλητή → χρησιμοποίησε .    |    Αν έχεις pointer → χρησιμοποίησε ->

📘 Παράδειγμα 5 — Αλλαγή Βαθμού μέσω Pointer

#include <stdio.h> /* ========================================= ΟΡΙΣΜΟΣ ΔΟΜΗΣ (Structure Definition) Δημιουργούμε έναν νέο τύπο δεδομένων Student ========================================= */ typedef struct { char name[50]; // όνομα φοιτητή int am; // αριθμός μητρώου float grade; // βαθμός } Student; /* ========================================= ΣΥΝΑΡΤΗΣΗ ΠΟΥ ΑΛΛΑΖΕΙ ΤΟΝ ΒΑΘΜΟ Function Definition Η συνάρτηση δέχεται POINTER σε δομή Student ========================================= */ void update_grade(Student *s, float new_grade) { /* s είναι POINTER σε δομή Student Student *s │ └─ δείκτης που δείχνει σε μια δομή Student */ s->grade = new_grade; /* s->grade σημαίνει: πήγαινε στη δομή που δείχνει ο pointer s και άλλαξε το πεδίο grade ισοδύναμο με: (*s).grade = new_grade */ /* έτσι αλλάζουμε τον βαθμό στην πραγματική μεταβλητή μνήμης */ } int main() { /* ========================================= ΔΗΜΙΟΥΡΓΙΑ ΜΕΤΑΒΛΗΤΗΣ ΔΟΜΗΣ ========================================= */ Student s1 = {"Νίκος", 1042, 6.0}; /* s1 είναι μεταβλητή δομής Student */ printf("Πριν : %.1f\n", s1.grade); /* εμφανίζει τον αρχικό βαθμό */ /* ========================================= ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΗΣ ========================================= */ update_grade(&s1, 8.5); /* &s1 σημαίνει: διεύθυνση μνήμης της μεταβλητής s1 περνάμε POINTER στη συνάρτηση ώστε να αλλάξει την πραγματική δομή */ printf("Μετά : %.1f\n", s1.grade); /* ο βαθμός έχει αλλάξει γιατί η συνάρτηση τροποποίησε τη δομή μέσω pointer */ return 0; }

👉 Εμφανίζει:

Πριν : 6.0 Μετά : 8.5

4.10 Πρακτικά Παραδείγματα

Παράδειγμα 6 — Βιβλίο (Τίτλος, Συγγραφέας, Τιμή)

struct Book
char[100]
title
τίτλος βιβλίου
char[60]
author
συγγραφέας
float
price
τιμή σε €
int
year
έτος έκδοσης
#include <stdio.h> typedef struct { char title[100]; char author[60]; float price; int year; } Book; int main() { Book library[3] = { {"Εισαγωγή στη C", "Kernighan", 35.00, 1988}, {"Αλγόριθμοι", "Cormen", 55.50, 2009}, {"Δομές Δεδομένων", "Μπάρδης", 30.00, 2024} }; int i; float total = 0; printf("%-30s %-15s Τιμή\n", "Τίτλος", "Συγγραφέας"); printf("------------------------------------------------\n"); for (i = 0; i < 3; i++) { printf("%-30s %-15s %.2f€\n", library[i].title, library[i].author, library[i].price); total += library[i].price; } printf("------------------------------------------------\n"); printf("Σύνολο: %.2f€\n", total); return 0; }

Παράδειγμα 7 — Ορθογώνιο (Υπολογισμός Εμβαδού)

#include <stdio.h> typedef struct { float width; /* πλάτος */ float height; /* ύψος */ } Rectangle; /* υπολογίζει εμβαδόν και επιστρέφει float */ float area(Rectangle r) { return r.width * r.height; } int main() { Rectangle rect = {5.0, 3.0}; /* πλάτος 5, ύψος 3 */ printf("Εμβαδόν: %.1f\n", area(rect)); return 0; }

👉 Εμφανίζει: Εμβαδόν: 15.0

📋 Σύνοψη Διάλεξης

Μετά από αυτή τη διάλεξη ξέρεις:

  • ✔ Πώς να ορίζεις μια struct με τα πεδία της
  • ✔ Πώς να δηλώνεις μεταβλητές και να αρχικοποιείς με { }
  • ✔ Πώς να προσπελάζεις πεδία με . και με ->
  • ✔ Πώς να χρησιμοποιείς typedef για απλούστερο κώδικα
  • ✔ Πώς να φτιάχνεις πίνακα από δομές
  • ✔ Πώς να περνάς δομές σε συναρτήσεις

Επόμενο Κεφάλαιο: Αρχεία (File I/O) — Αποθήκευση δεδομένων στο δίσκο

4.11 Ασκήσεις

🔥 Ασκήσεις για Εμπέδωση

  1. Δημιούργησε μια δομή Car με πεδία: brand (char[30]), year (int), price (float). Δήλωσε δύο αυτοκίνητα και εκτύπωσε τα στοιχεία τους.
  2. Φτιάξε πίνακα 5 φοιτητών. Διάβασε τα δεδομένα από τον χρήστη και βρες τον φοιτητή με τον υψηλότερο βαθμό.
  3. Γράψε μια συνάρτηση compare_grades που δέχεται δύο δομές Student και επιστρέφει τον φοιτητή με τον καλύτερο βαθμό.
  4. Δημιούργησε δομή Point με x, y (float). Γράψε συνάρτηση που υπολογίζει την αποστάση μεταξύ δύο σημείων.
  5. (Δύσκολο) Φτιάξε δομή Employee με name, salary, department. Ταξινόμησε πίνακα υπαλλήλων κατά αλφαβητική σειρά ονόματος.

📊 Πίνακας Ανακεφαλαίωσης Συντάξεων

Ενέργεια Σύνταξη Παράδειγμα
Ορισμός δομής typedef struct { ... } Name; typedef struct { int x; } Point;
Δήλωση μεταβλητής Name var; Student s1;
Αρχικοποίηση Name var = {val1, val2}; Student s = {"Νίκος", 1, 8.0};
Πρόσβαση (μεταβλητή) var.field s.grade = 9.0;
Πρόσβαση (pointer) ptr->field ptr->grade = 9.0;
Πίνακας δομών Name arr[N]; Student arr[30];