Δημοσιεύτηκε: 07 Σεπ 2011, 11:36
Star_Light έγραψε:Να ρωτησω κατι τελευταιο με τους ελεγχους και τα if , γιατι θες να ελεγχεις να μην ειναι NULL Ο δεικτης πριν τον ελευθερωσεις ?
Γιατί σε παλαιότερες αναθεωρήσεις της γλώσσας η συνάρτηση free( p ) επιχειρούσε να πειράξει τα περιεχόμενά του p χωρίς να ελέγχει πρώτα αν o p είναι NULL, οπότε αν ήταν NULL (δεν είχε δλδ περιεχόμενα) παρήγαγε seg-fault. Σε νεότερες αναθεωρήσεις έχει μπει στα στάνταρ να κάνει τον έλεγχο αυτόν η free() αλλά όπως έχουμε πει δεν ακολουθούν όλοι οι compilers όλα τα νέα στάνταρ.
έγραψε:Και αμεσως μετα (αν ειναι) να τον κανεις NULL πχ.
Αμέσως μετά την απελευθέρωσή του εννοούμε. Τον κάνεις NULL για να μη ρισκάρεις να χρησιμοποιηθεί αργότερα με undefined περιεχόμενα, σε μεταγενέστερα σημεία του κώδικα ( free() δεν κάνουμε μόνο πριν τερματίσουμε, πολύ συχνά κάνουμε και σε άλλα σημεία του προγράμματός μας).
έγραψε:ΕΠισης εκει που λες οτι το ανύπαρκτο ειναι παντα μικρότερο του υπαρκτού εκει κάνεις έλεγχο αν το s1 (ανύπαρκτο) ειναι η εισοδος s1[]="";
δηλαδη ενα string που έχει μονο τον κενο χαρακτηρα.... που ειναι το 0 και επομένωςSpoiler: show
αυτη ειναι η λογικη ????
Κοίτα, με αυτή την ερώτηση καταλαβαίνω πως ακόμα δεν τα έχεις ξεκαθαρίσει. Καταρχήν ο δείκτης s1 στο s1[]="" είναι υπαρκτός δείκτης (δηλαδή δεν είναι NULL) και έπειτα το μήκος του s2[]="ab" δεν είναι 2... 2 είναι το μήκος των ωφέλιμων χαρακτήρων του, αλλά το συνολικό του μήκος είναι 3, αφού υπάρχει και ο μηδενικός χαρακτήρας στο τέλος.
Λοιπόν, ας το πούμε αλλιώς, ένας δείκτης που έχει οριστεί μπορεί γενικώς να βρίσκεται σε 2 καταστάσεις:
- έγκυρος: όταν δείχνει είτε σε NULL ( p = NULL ), είτε σε μνήμη που έχει δημιουργηθεί ειδικά για τον δείκτη ( p = calloc(...) ), είτε σε μνήμη μιας άλλης έγκυρης μεταβλητής ( p = &var ή p = array )
- άκυρος: όταν δείχνει σε μη-έγκυρη μνήμη... δείχνει δηλαδή σε undefined περιοχή μνήμης, ή αν το προτιμάς σαν ορολογία έχει undefined περιεχόμενο (π.χ. int *p; ή free(p) )
Σε αυτό το σημείο είναι πολύ σημαντικό να ξεκαθαρίσετε πως το NULL είναι ΕΓΚΥΡΟΣ δείκτης, αλλά ΔΕΝ ΕΧΕΙ ΠΕΡΙΕΧΟΜΕΝΑ! Οπότε οποιαδήποτε απόπειρα να χρησιμοποιήσετε τα περιεχόμενα ( *p ) ενός δείκτη p που είναι NULL παράγει seg-fault ! Οπότε μπορούμε να χαρακτηρίσουμε έναν έγκυρο δείκτη NULL ως ανύπαρκτο, υπό την έννοια πως δεν έχει υπαρκτά περιεχόμενα! Από την άλλη μεριά, ένας δείκτης με υπαρκτά περιεχόμενα δεν είναι κατά ανάγκην και έγκυρος! Αν τα περιεχόμενά του είναι undefined τότε o δείκτης είναι άκυρος (undefined περιεχόμενα παίρνει ένας δείκτης όταν τον κάνουμε free() ή όταν τον ορίζουμε αλλά χωρίς να τον βάλουμε μετά να δείχνει κάπου).
Άρα λοιπόν στην s_compare() με τα early-exit conditions που προσέθεσα εξασφαλίζω αφενός πως η συνάρτησή μας δεν θα παράξει seg-fault αν της περαστεί έστω κι ένα από τα ορίσματά της ως NULL, κι αφετέρου πως όταν η ροή φτάσει στον βασικό αλγόριθμο της συνάρτησης και οι δυο δείκτες θα δείχνουν σε υπαρκτά περιεχόμενα. Το αν αυτά τα περιεχόμενα είναι έγκυρα ή άκυρα η συνάρτηση δεν μπορεί να το ελέγξει, αυτή η εξασφάλιση είναι ευθύνη της ρουτίνας που καλεί τη συνάρτηση.
Οπότε για να απαντήσω και στην ερώτησή σου σχετικά με τη σύγκριση NULL και μη NULL δεικτών στην s_compare(), θεωρώ αυθαίρετα (αλλά σύμφωνα με τη γενικότερη λογική της συνάρτησης) πως ένας δείκτης με ανύπαρκτα περιεχόμενα είναι μικρότερος από έναν άλλον που έχει υπαρκτά περιεχόμενα (δηλαδή πως το NULL είναι μικρότερο του !NULL ... που btw συνήθως ισχύει κιόλας
Η παραπάνω λογική εφαρμόζεται άμεσα και τερματίζει την συνάρτηση με τα 3 if που πρόσθεσα στην αρχή της. Η όλη ιστορία γίνεται ακριβώς για να μην επιχειρήσει ο βασικός μας αλγόριθμος να χρησιμοποιήσει ανύπαρκτα περιεχόμενα δεικτών ( *s1 ή *s2) ... να μην μπει καν δηλαδή στη διαδικασία ελέγχου μεμονωμένων χαρακτήρων στα strings ... άρα το παράδειγμα που έγραψες παραπάνω για την απορία σου είναι τελείως εκτός συγκριτικά με τα όσα είπαμε στα 2-3 προηγούμενα posts ( δεν το εννοώ υποτιμητικά, αυτό έλειπε... το λέω ως συνέχεια αυτού που έγραψα στην αρχή πως με αυτή την ερώτηση κατάλαβα πως δεν τα έχεις ακόμα ξεκαθαρισμένα ).
Ξεκαθάρισαν τώρα;