Δημοσιεύτηκε: 10 Σεπ 2011, 20:27
από migf1
Μέχρι να κάνετε τους ελέγχους ασφάλειας στις μέχρι τώρα συναρτήσεις μας, να πω μερικά πράγματα για την επόμενη.

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

Αν και νομίζω ξέρετε ήδη τι είναι οι δομές (struct) εν τάχει λέω τα βασικά.

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

Ένα κλασικό κι απλό παράδειγμα χρήσης δομής είναι όταν θέλουμε να διαχειριστούμε συντεταγμένες. Ας πούμε το πρόγραμμά μας θα ασχοληθεί με σημεία του καρτεσιανού επιπέδου, που το καθένα έχει μια x και μια y συντεταγμένη.

Αντί λοιπόν να χρησιμοποιούμε "ξέμπαρκες" μεταβλητές για τις συντεταγμένες ενός σημείου, μπορούμε να φτιάξουμε μια δομή που θα την ονομάσουμε π.χ. point και θα αποτελείται από 2 int, ένα για τη συντεταγμένη x κι έναν για την συντεταγμένη y...

Κώδικας: Επιλογή όλων

// ορισμός της δομής struct point
struct point {
int x;
int y;
};

Οπότε στο πρόγραμμά μας μπορούμε τώρα να γράψουμε κάτι σαν το παρακάτω...
Κώδικας: Επιλογή όλων

#include <stdio.h>

// ορισμός της δομής struct point
struct point {
int x;
int y;
};

/* ----------------------------------------------------------- */
int main( void )
{
struct point a, b; // ορισμός 2 σημείων a και b
...
a.x = 10;
a.y = 12;

b.x = 100;
b.y = 12;
...

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

struct point a;
a.x = 10;

Αν η μεταβλητή μας όμως δεν είναι απλή μεταβλητή αλλά δείκτης, τότε για να αναφερθούμε σε ένα πεδίο της αντί για τελεία χρησιμοποιούμε το σύμβολο ->

Κώδικας: Επιλογή όλων

#include <stdio.h>

// ορισμός της δομής struct point
struct point {
int x;
int y;
};

/* ----------------------------------------------------------- */
int main( void )
{
struct point *a = NULL; // ορισμός ενός σημείου a ως δείκτη σε δομή struct point

a = calloc(1, sizeof( struct point ) );
if ( !a ) {
// διαχειριστείτε εδώ ενδεχόμενη αποτυχία δέσμευση μνήμης για το a
}
a->x = 10;
a->y = 12;
...
if ( a )
free( a );
a = NULL;
}

return 0;
}

Και για να μην "κουβαλάμε" συνέχεια το keyword struct όποτε χρειάζεται να αναφερθούμε στον τύπο της δομής, όταν την πρωτο-ορίζουμε μπορούμε να την δηλώσουμε ως δικό μας επιπρόσθετο τύπο δεδομένων, με την χρήση του typedef..

Κώδικας: Επιλογή όλων

#include <stdio.h>

// ορισμός & κατοχύρωση της δομής struct point ως πρόσθετο τύπο δεδομένων με το όνομα Point
typedef struct point {
int x;
int y;
} Point;

/* ----------------------------------------------------------- */
int main( void )
{
Point *a = NULL; // ορισμός ενός σημείου a ως δείκτη σε δομή struct point

a = calloc(1, sizeof( Point ) );
if ( !a ) {
// διαχειριστείτε εδώ ενδεχόμενη αποτυχία δέσμευση μνήμης για το a
}
a->x = 10;
a->y = 12;
...
if ( a )
free( a );
a = NULL;
}

return 0;
}

Ελπίζω να είναι όλα κατανοητά μέχρι εδώ (τα έχουμε χρησιμοποιήσει άλλωστε ήδη πολλές φορές :) )

Πού είναι όμως το κέρδος της ομαδοποίησης; Αφού και χωρίς δομή πάλι 2 μεταβλητές θα χρησιμοποιούσαμε για τις συντεταγμένες κάθε σημείου, 2 χρησιμοποιούμε και τώρα.. και μάλιστα και με πιο περίεργη σύνταξη :lol:

Το κέρδος της ομαδοποίησης γίνεται εμφανές όταν περνάμε τις μεταβλητές ως ορίσματα σε συναρτήσεις. Φανταστείτε για παράδειγμα ότι στο παραπάνω πρόγραμμα θέλαμε να φτιάξουμε μια συνάρτηση draw_line() η οποία θα παίρνει για ορίσματα 2 σημεία και θα τα ενώνει με μια γραμμή.

Χωρίς τη δομή θα έπρεπε να περάσουμε στη συνάρτηση 4 ορίσματα, 2 για κάθε σημείο... π.χ...
Κώδικας: Επιλογή όλων

draw_line( int ax, int ay, int bx, int by );

ενώ με τη δομή μπορούμε να περάσουμε μόνο 2 ορίσματα...
Κώδικας: Επιλογή όλων

draw_line( Point a, Point b );

Το δεύτερο εκτός από πιο δομημένο είναι και πολύ πιο ευανάγνωστο, δεν συμφωνείτε; :) Κυρίως όμως είναι πιο εύκολα διαχειρίσιμο, ειδικά σε πολύπλοκα προγράμματα!

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