Καλημέρες, καλημέρες

Λοιπόν δίνω σε spoiler την υλοποίηση της
table_print_contents() για να συνεχίσουμε...
- Κώδικας: Επιλογή όλων
/* --------------------------------------------------------------------------------
* Τυπώνει τα μη κενά στοιχεία του πίνακα table
* --------------------------------------------------------------------------------
*/
void table_print_contents( int *table, const int maxelems )
{
register int i = 0;
for (i=0; i < maxelems; i++)
if ( table[i] != EMPTYELEM )
printf( "%d ", table[i] );
putchar('\n');
return;
}
Θα προσπαθήσω ο κώδικας που φτιάχνουμε να είναι συμβατός με το στάνταρ ANSI (C89) που το υποστηρίζουν όλοι οι compilers (σε αντίθεση με το c99 που και δεν το υποστηρίζουν όλοι και όσοι το υποστηρίζουν το υποστηρίζουν μερικώς). Για αυτό αν προσέξατε τα σχόλια τα έχω σε /* */ και όχι σε //
Πάει αυτό

Το επόμενο είναι πως σας είχα πει να χρησιμοποιείται πάντα την calloc() αντί της malloc() όταν θέλετε να δεσμεύετε δυναμικά μνήμη για κάποιον δείκτη, επειδή η calloc() μηδενίζει εγγυημένα τα περιεχόμενα της μνήμης που δεσμεύει (βάζει την τιμή 0 σε όλα τα bytes που δεσμεύει). Αντίθετα, τα περιεχόμενα της μνήμης που δεσμεύονται με την malloc() είναι undefined (μπορεί δλδ να περιέχουν οτιδήποτε)!
Όμως στον κώδικα που έδωσα για να ξεκινήσουμε, τη μνήμη του table τη δεσμεύω με malloc() και όχι με calloc()... δάσκαλε που δίδασκες δηλαδή

Περίμενα να με ρωτήσετε για αυτό, αλλά είδα πως "δεν" οπότε το σημειώνω μόνος μου

Λοιπόν ο λόγος που χρησιμοποίησα malloc() αντί για calloc() είναι πως τα αρχικά περιεχόμενα του table δεν τα θέλουμε να είναι 0, αλλά EMPTYELEM (που το έχουμε βάλει να ισούται με -1). Άρα και με calloc() να δέσμευα τη μνήμη θα χρειαζόταν έτσι κι αλλιώς μετά να πάω να βάλω σε όλα τα στοιχεία του πίνακα την τιμή EMPTYELEM

Τώρα, αυτό το γέμισμα όλων των στοιχείων του πίνακα με την ίδια τιμή (που στην προκειμένη περίπτωση είναι η EMPTYELEM) μπορούμε να την κάνουμε φτιάχνοντας μια συνάρτηση, π.χ.
- Κώδικας: Επιλογή όλων
void table_fill_same( int *table, const int maxelems, const int value )
{
register int i = 0;
for (i=0; i < maxelems; i++)
table[ i ] = value;
}
return;
}
που θα έπιανε τον πίνακα από το στοιχείο 0 και μέχρι να φτάσει στο στοιχείο maxelems-1 θα έβαζε στο κάθε στοιχείο την τιμή value... προφανώς όταν καλούσαμε την συνάρτηση αυτή θα της περνάγαμε ως value το EMPTYELEM.
Αυτός είναι ο κλασικός τρόπος γεμίσματος ενός πίνακα με την ίδια τιμή σε όλα του τα στοιχεία. Είναι όμως αργός τρόπος! Ο ταχύτερος τρόπος να γεμίζουμε ένα κομμάτι μνήμης με την ίδια τιμή στη C είναι με τη στάνταρ συνάρτηση...
- Κώδικας: Επιλογή όλων
void * memset (void *block, int c, size_t size)
- block είναι η αρχή της μνήμης που μας ενδιαφέρει να γεμίσουμε με μια τιμή (η αρχή της μνήμης είναι ένας δείκτης - αδιάφορου τύπου, εξού και το void * - για τον οποίον έχουμε ήδη δεσμεύσει μνήμη... μπορούμε να περάσουμε εδώ και το όνομα ενός απλού πίνακα)
- c είναι η τιμή που θέλουμε να περάσουμε σε όλα τα στοιχεία του block
- size είναι το μέγεθος της μνήμης που θέλουμε να γεμίσουμε, αλλά ΠΡΟΣΟΧΗ εκφρασμένο σε bytes και ΟΧΙ σε πλήθος στοιχείων
Στον κώδικα που έδωσα λοιπόν γεμίζω όλα τα στοιχεία του πίνακα table με την τιμή EMPTYELEM, χρησιμοποιώντας την έτοιμη και ταχύτατη memset() ... χρειάζεται #include <string.h> στην αρχή του προγράμματος.
ΣΗΜΕΙΩΣΤΕ πως ως 3ο όρισμα δεν της περνάω το μέγιστο πλήθος στοιχείων του πίνακά μας ( maxelems ) αλλά το μέγεθος που καταλαμβάνουν σε bytes στη μνήμη ( maxelems * sizeof(int) ) το οποίο απλά το έχω υπολογίσει από πριν και το έχω αποθηκεύσει στη μεταβλητή tabsize.
Είναι κρίσιμης σημασίας να διαχωρίσετε στο μυαλό σας πως άλλο είναι το πλήθος στοιχείων ενός πίνακα και άλλο το μέγεθος που πιάνουν στη μνήμη σε bytes.
Για παράδειγμα αν ο πίνακάς μας ήταν πίνακας χαρακτήρων, τότε το κάθε στοιχείο του θα έπιανε 1 byte (οι char είναι 1 byte) οπότε σε αυτή την περίπτωση το πλήθος των στοιχείων του πίνακα ταυτίζεται με το συνολικό μέγεθος που καταλαμβάνουν στη μνήμη. Εμείς όμως έχουμε πίνακα από int, και ο κάθε int καταλαμβάνει τουλάχιστον 2 bytes (και αλλάζει ανάλογα την πλατφόρμα) οπότε είναι προφανές πως σε αυτή την περίπτωση το μέγεθος που καταλαμβάνει ο πίνακας σε bytes στη μνήμη ΔΕΝ ταυτίζεται ως νούμερο με το πλήθος των στοιχείων του.
Συνήθως η ορολογία που χρησιμοποιείται για να διαχωρίζει τα 2 αυτά πράγματα είναι:
length για το πλήθος στοιχείων και
size για την μνήμη που καταλαμβάνουν σε bytes.
Η memset() ( όπως και οι memcpy() και memmove() ) είναι από τις πιο πολυ-χρησιμοποιούμενες συναρτήσεις στη C και θα τις χρησιμοποιήσουμε κι εμείς σε αυτό το πρόγραμμα. Συνιστώ να εξοικειωθείτε πρώτα με την memset() διαβάζοντας την τεκμηρίωσή της και κάνοντας όσες δοκιμές χρειαστούν προκειμένου να κατανοήσετε τη λειτουργία της !
Ανεξάρτητα από την memset() στο επόμενο ποστ δίνω την επόμενη άσκηση (btw, αυτό που κάνουμε τώρα έπρεπε να το είχαμε κάνει πολύ νωρίτερα!!! νομίζω είναι ο καλύτερος τρόπος να εμβαθύνουμε σταδιακά σε πολλά χαρακτηριστικά της γλώσσας, έχοντας κι ένα στόχο που τον χτίζουμε κομμάτι-κομμάτι

)