Δημοσιεύτηκε: 13 Αύγ 2011, 06:38
από migf1
stamatiou έγραψε:Εγώ αυτό που δεν καταλαβαίνω στον κώδικα είναι ότι:
1. Στην arrisfull arrisempty ελέγχει εάν στην πρώτη το περιεχόμενο είναι 0 αλλά αν είναι 0 ο πρώτος χαρακτήρας αν είναι 0 δεν σημαίνει ότι είναι άδειος ο πίνακας και το ίδιο για την arrisfull.
2. Στη arrisempty ελέγχεις το χαρακτήρα πριν το lenght, στο lenght συμπεριλαμβάνεται το '\0' και αν όχι γιατί ελέγχεις το len-1;

Έχεις δίκιο που μπερδεύτηκες, γιατί το πρόγραμμα ήρθε αμέσως μετά τα strings. Βασικά εδώ δεν έχουμε string αλλά έναν απλό πίνακα από int (δηλαδή όχι από char).

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

Ίσως το 0 να μην είναι καλή επιλογή. Αν θεωρήσουμε ότι ο πίνακάς μας φτιάχνεται για να δέχεται αποκλειστικά θετικές τιμές ή 0, τότε μπορούμε να αλλάξουμε την EMPTY_ELEMVAL π.χ. σε -1. Οπότε όποιο στοιχείο του πίνακα βλέπουμε πως έχει αυτή τη τιμή, το θεωρούμε κενό.

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

Επιστρέφοντας λίγο πάλι στη λογική του προγράμματος, θεωρούμε πως ο πίνακάς μας ξεκινάει κενός, π.χ. με τιμές {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} και όταν δεν είναι κενός οι τιμές που περιέχει είναι συνεχόμενες ξεκινώντας από την αρχή του. Δηλαδή, αν προσθέσουμε για παράδειγμα τις τιμές 99 και 1000 θα πρέπει να μπουν στις 2 πρώτες θέσεις του και οι υπόλοιπες θα παραμείνουν κενές (δηλαδή με τιμή EMPTY_ELEMVAL).

Οπότε με αυτές τις διευκρινήσεις, νομίζω γίνεται πιο εμφανής ο ρόλος των ARR_ISFULL() και ARR_ISEMPTY(). Αν όχι, εδώ είμαστε :)

Για τη 2η ερώτησή τώρα, όταν π.χ. το συνολικό μήκος του πίνακα είναι 10 στοιχεία, το τελευταίο του στοιχείο είναι το 9 (και όχι το 10) γιατί η αρίθμηση των θέσεων ξεκινάει από το 0.

Btw, τα έγραψες ανάποδα, το ARR_ISEMPTY() ελέγχει την 1η θέση αν είναι EMPTY_ELEMVAL, ενώ το ARR_ISFULL() ελέγχει την τελευταία θέση αν είναι EMPTY_ELEMVAL ;)

Όταν κατανοήσετε πως ακριβώς δουλεύουν οι συναρτήσεις, μπορείτε να φτιάξετε άλλη μια που θα μηδενίζει μονομιάς όλα τα στοιχεία του πίνακα, θα τους βάζει δηλαδή την τιμή EMPTY_ELEMVAL. Τώρα που η EMPTY_ELEMVAL ισούται με 0 ο μηδενισμός του πίνακα μπορεί να γινει πολύ γρήγορα με τη συνάρτηση memset (που την έχω σε σχόλια) αλλά η memset δεν μπορεί να βάλει αρνητικές τιμές. Οπότε αν π.χ. το EMPTY_ELEMVAL θέλετε να το αλλάξετε ας πούμε σε -1, θα χρειαστεί να φτιάξετε μια δικιά σας συνάρτηση, π.χ. void arr_reset(int arr, int maxelems);

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

Για παράδειγμα, αν ο πίνακας έχει την μορφή: {90, 20, 30, 0, 0, 0, 0, 0, 0, 0} τότε το τρέχον μήκος του είναι 3, διότι έχει τιμές στα 3 πρώτα στοιχεία του.

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

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

Για παράδειγμα:

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

#define MAX_ELEMENTS 10
#define EMPTY_ELEMVAL 0

#define ARR_ISEMPTY(arr) ( (arr)[0] == EMPTY_ELEMVAL )
#define ARR_ISFULL(arr, maxlen) ( (arr)[(maxlen)-1] != EMPTY_ELEMVAL )

typedef struct {
int len;
int arr[ MAX_ELEMENTS] ;
} List;

// -----------------------------------------------------------------------------
void list_reset( List *list, int maxelems)
{
register int i;

for (i=0; i<maxelems; i++)
list->arr[i] = EMPTY_ELEMVAL;
list->len = 0;

return;
}
// -------------------------------------------------------------------------------------
int list_append( List *list, int maxelems, int val)
{
if ( ARR_ISFULL( list->arr, maxelems ) )
return -1;

if ( ARR_ISEMPTY( list->arr ) ) {
list->arr[0] = val;
list->len = 1;
return 0;
}

register int i;
for (i=maxelems-1; list->arr[i] == EMPTY_ELEMVAL; i--)
;
list->arr[++i] = val;
(list->len)++;

return i;
}
// -------------------------------------------------------------------------------------
void list_print( List list, int maxelems )
{
register int i;

for (i=0; i < maxelems; i++)
printf("%d ", list.arr[i] );
putchar('\n');

return;
}
// -----------------------------------------------------------------------------
int main( void )
{
List mylist;

list_reset( &mylist, MAX_ELEMENTS);
list_append( &mylist, MAX_ELEMENTS, 999);
list_print( mylist, MAX_ELEMENTS );

return 0;
}

Βασικά αν κρατάμε ενημερωμένο το list->len, τότε η list_append() γίνεται πανεύκολη, διότι απλά τσεκάρουμε να μην είναι κενός ο πίνακας και κατόπιν γράφουμε: list->arr[ list->len ] = val; (list->len)++;

Αλλά πριν πάμε σε αυτά, βεβαιωθείτε πως καταλαβαίνετε πως λειτουργούν οι συναρτήσεις στο αρχικό πρόγραμμα (βάλτε σχόλια δίπλα σε ΚΑΘΕ γραμμή).

@starlight: δώσε :)