migf1 έγραψε:Για να ολοκληρώσουμε λοιπόν και το θέμα των ελέγχων που έχουμε αφήσει ανοιχτό στη συνάρτηση s_compare που έχουμε φτιάξει, παραθέτω τον ολοκληρωμένο της κώδικα, κι εξηγώ από κάτω...
- Κώδικας: Επιλογή όλων
// ------------------------------------------------------------------------------------
int s_compare( const char *s1, const char *s2 )
{
if ( !s1 && !s2 )
return 0;
if ( !s1 && s2 )
return -1;
if (s1 && !s2 )
return 1;
while ( *s1 == *s2++ )
if ( *s1++ == '\0' )
return 0;
return (int) ( *s1 - *--s2 );
}
Οι έλεγχοι αυτοί είναι όλοι early-exit conditions και αποτελούνται από τα 3 if που έχω προσθέσει στην αρχή της συνάρτησης.
Στο πρώτο ελέγχω αν και ο δείκτης s1 και ο δείκτης s2 είναι NULL (που ουσιαστικά είναι τα 2 strings που μας έχουν περαστεί στη συνάρτηση και καλούμαστε να τα συγκρίνουμε). Όταν λοιπόν είναι και τα 2 NULL, δηλαδή ανύπαρκτα επί της ουσίας, τότε επιστρέφω την τιμή 0... σαν να υπήρχαν δηλαδή και να ήταν ίδια.
Στο 2ο if ελέγχω την περίπτωση όπου το s1 είναι NULL αλλά το s2 υπάρχει (και προφανώς περιέχει κάτι). Σε αυτή την περίπτωση θεωρώ πως το s1 είναι μικρότερο του s2 (με τη λογική πως το ανύπαρκτο είναι πάντα μικρότερο του υπαρκτού) οπότε επιστρέφω την τιμή -1.
Και στο 3ο if εξετάζω την περίπtωση όπου το s1 είναι υπαρκτό και το s2 ανύπαρκτο, οπότε θεωρώ το s1 μεγαλύτερο του s2 κι επιστρέφω την τιμή 1.
Αν η ροή καταφέρει και περάσει από αυτούς τους ελέγχους, τότε έχουμε εγγυημένα 2 υπαρκτά stings (μη NULL) και άρα μπορούμε να γράψουμε τον βασικό αλγόριθμο της συνάρτησής μας, χωρίς να μας απασχολεί πλέον αν κάποιο ή και τα 2 strings που μας περάστηκαν σαν ορίσματα είναι NULL.
Έχουμε καταφέρει επίσης να αποφύγουμε τυχόν παραγωγή segmentation-faults, διότι δεν υπάρχει καμία πιθανότητα ο κώδικάς μας να επιχειρήσει να χρησιμοποιήσει κάποιο από τα s1 και s2 όταν οποιοδήποτε από αυτά είναι NULL.
Άρα έχουμε φτιάξει μια λειτουργική και ΑΣΦΑΛΗ συνάρτηση!
Υπάρχει κάποια πιθανότητα να παραχθεί seg-fault, αν για παράδειγμα κάποιο ή και τα δυο από τα s1 και s2 ναι μεν δεν είναι NULL, αλλά δεν δείχνει σε έγκυρη μνήμη. Π.χ. να έχει οριστεί στη main() χωρίς να έχει αρχικοποιηθεί ούτε σε NULL αλλά ούτε με calloc() / malloc()... και να έχει περαστεί έτσι στη συνάρτησή μας.
Αυτό όμως δεν μπορεί να το γνωρίζει η συνάρτηση, ούτε μπορεί να το ελέγξει. Οπότε ότι είχαμε να κάνουμε σε επίπεδο συνάρτησης το έχουμε κάνε!, Μένει να εξασφαλίσουμε πως τα s1 και s2 θα είναι είτε NULL είτε θα δείχνουν σε έγκυρη μνήμη όταν καλούμε τη συνάρτηση και της τα περνάμε σαν ορίσματα!
Θέλω να πιστεύω πως είναι κατανοητό πλέον. Αν όχι πείτε το, για να προχωρήσουμε.
Μετά το βρόχο του while δεν πάει το s1 1 θέση μετά το '\0';



