[Powered by Google Translate] [CS50 Βιβλιοθήκη]
[Nate Hardison] [Πανεπιστήμιο του Χάρβαρντ]
[Αυτό είναι CS50. CS50.TV]
Η βιβλιοθήκη CS50 είναι ένα χρήσιμο εργαλείο που έχουμε εγκαταστήσει στη συσκευή
ώστε να είναι ευκολότερο για σας να γράψετε προγράμματα που ζητούν από τους χρήστες για την είσοδο.
Σε αυτό το βίντεο, θα τραβήξει την κουρτίνα και να δούμε τι ακριβώς είναι το CS50 βιβλιοθήκη.
>> Στο βίντεο για βιβλιοθήκες C, μιλάμε για το πώς θα περιλαμβάνουν # κεφαλίδες αρχεία
της βιβλιοθήκης στον πηγαίο κώδικα σας,
και στη συνέχεια να συνδεθεί με ένα δυαδικό αρχείο της βιβλιοθήκης κατά τη διάρκεια της σύνδεσης φάση
της διαδικασίας κατάρτισης.
Τα αρχεία κεφαλίδας καθορίσετε τη διασύνδεση της βιβλιοθήκης.
Δηλαδή, λεπτομερώς όλους τους πόρους που η βιβλιοθήκη έχει στη διάθεσή της για να το χρησιμοποιήσετε,
όπως οι δηλώσεις λειτουργία, σταθερές και τύπους δεδομένων.
Το δυαδικό αρχείο βιβλιοθήκης περιέχει την εφαρμογή της βιβλιοθήκης,
η οποία έχει συνταχθεί από τα αρχεία κεφαλίδας της βιβλιοθήκης και της βιβλιοθήκης. γ. αρχεία πηγαίου κώδικα.
>> Το δυαδικό αρχείο της βιβλιοθήκης δεν είναι πολύ ενδιαφέρον να δούμε δεδομένου ότι είναι, επίσης, σε δυαδικό.
Έτσι, ας ρίξουμε μια ματιά στα αρχεία κεφαλίδας για τη βιβλιοθήκη αντ 'αυτού.
Σε αυτή την περίπτωση, υπάρχει μόνο ένα αρχείο κεφαλίδας που ονομάζεται cs50.h.
Έχουμε εγκαταστήσει στο χρήστη περιλαμβάνουν κατάλογο
μαζί με τα αρχεία επικεφαλίδων των άλλων βιβλιοθηκών του συστήματος ».
>> Ένα από τα πρώτα πράγματα που θα παρατηρήσετε είναι ότι περιλαμβάνει cs50.h # header αρχεία από άλλες βιβλιοθήκες -
float, όρια, bool πρότυπο, πρότυπο και lib.
Και πάλι, μετά από την αρχή του δεν ανακαλύπτουμε τον τροχό,
έχουμε χτίσει την CS0 βιβλιοθήκη χρησιμοποιώντας τα εργαλεία που παρέχονται για άλλα μας.
>> Το επόμενο πράγμα που θα δείτε στη βιβλιοθήκη είναι ότι ορίζουμε ένα νέο είδος που ονομάζεται "string".
Αυτή η γραμμή δημιουργεί πραγματικά ακριβώς ένα ψευδώνυμο για τον τύπο char *,
έτσι δεν εμπνέει μαγικά το νέο τύπο string με χαρακτηριστικά
συνήθως συνδέεται με αντικείμενα εγχόρδων σε άλλες γλώσσες,
όπως το μήκος.
Ο λόγος που έχουμε κάνει είναι να προστατεύσει νέα προγραμματιστές από τις φρικιαστικές λεπτομέρειες
των δεικτών, έως ότου είστε έτοιμοι.
>> Το επόμενο μέρος του αρχείου κεφαλίδας είναι η δήλωση των λειτουργιών
ότι η CS50 βιβλιοθήκη παρέχει μαζί με την τεκμηρίωση.
Παρατηρήστε το επίπεδο της λεπτομέρειας στα σχόλια εδώ.
Αυτό είναι εξαιρετικά σημαντικό, έτσι ώστε οι άνθρωποι ξέρουν πώς να χρησιμοποιούν αυτές τις λειτουργίες.
Δηλώνουμε, με τη σειρά του, να λειτουργεί ζητήσει από το χρήστη και χαρακτήρες επιστροφής, δίκλινα, πλωτήρες, ints,
πολύ λαχταρά, και έγχορδα, χρησιμοποιώντας το δικό μας τύπο string.
Σύμφωνα με την αρχή της απόκρυψης πληροφοριών,
έχουμε θέσει τον ορισμό μας σε ένα ξεχωριστό αρχείο εφαρμογής c -. cs50.c--
βρίσκεται στον πηγαίο κατάλογο του χρήστη.
Έχουμε υπό την προϋπόθεση ότι το αρχείο ώστε να μπορείτε να ρίξετε μια ματιά σε αυτό,
να μάθουν από αυτό, και το μεταγλωττίσετε σε διαφορετικές μηχανές, αν θέλετε,
παρόλο που πιστεύω ότι είναι καλύτερα να εργαστούν για τη συσκευή για αυτή την κατηγορία.
Τέλος πάντων, ας ρίξουμε μια ματιά σε αυτό τώρα.
>> Οι λειτουργίες getchar, GetDouble, GetFloat, GetInt, και GetLongLong
είναι όλα χτισμένα στην κορυφή της GetString λειτουργία.
Αποδεικνύεται ότι ουσιαστικά όλοι ακολουθούν το ίδιο μοτίβο.
Χρησιμοποιούν ένα βρόχο while να ζητήσει από το χρήστη για μία γραμμή εισόδου.
Επιστρέφουν μια ιδιαίτερη αξία αν ο χρήστης εισάγει μια κενή γραμμή.
Προσπαθούν να αναλύσει είσοδο του χρήστη ως τον κατάλληλο τύπο,
είτε πρόκειται για ένα char, ένα διπλό, ένα float, κλπ.
Και τότε θα επιστρέψουν είτε το αποτέλεσμα αν η είσοδος με επιτυχία αναλύονται
ή μπορούν reprompt το χρήστη.
>> Σε υψηλό επίπεδο, δεν υπάρχει τίποτα πραγματικά δύσκολο εδώ.
Μπορεί να έχετε γράψει τον εαυτό σας με παρόμοια δομή κώδικα στο παρελθόν.
Ίσως το πιο αινιγματικό μέλλον είναι το μέρος sscanf κλήση που αναλύει είσοδο του χρήστη.
Sscanf είναι μέρος της οικογένειας με τη μορφή μετατροπής εισόδου.
Ζει σε io.h πρότυπο, και η δουλειά του είναι να αναλύσει μια σειρά C,
σύμφωνα με μια συγκεκριμένη μορφή, η αποθήκευση των αποτελεσμάτων μεταγλώττιση στη μεταβλητή
που παρέχεται από τον καλούντα.
Δεδομένου ότι οι λειτουργίες μετατροπής μορφή εισόδου είναι πολύ χρήσιμα, ευρέως χρησιμοποιούμενες λειτουργίες
που δεν είναι σούπερ διαισθητική κατά την πρώτη,
θα πάμε πέρα ​​από το πώς λειτουργεί sscanf.
>> Το πρώτο επιχείρημα είναι να sscanf ένα char * - ένας δείκτης σε χαρακτήρα.
Για τη λειτουργία να λειτουργήσει σωστά,
ότι ο χαρακτήρας θα πρέπει να είναι ο πρώτος χαρακτήρας της σειράς C,
τερματίζεται με το null \ 0 χαρακτήρας.
Αυτή είναι η σειρά να αναλύσει
Το δεύτερο επιχείρημα για sscanf είναι μια συμβολοσειρά μορφής,
συνήθως πέρασε ως σταθερή σειρά,
και μπορεί να έχετε δει μια σειρά, όπως αυτό πριν, όταν χρησιμοποιεί το printf.
Ένα σημάδι τοις εκατό στη σειρά σχήμα δείχνει έναν προσδιοριστή μετατροπής.
Ο χαρακτήρας αμέσως μετά το σύμβολο του ποσοστού,
δηλώνει ο τύπος C που θέλουμε sscanf να μετατρέψετε σε.
Σε GetInt, θα δείτε ότι υπάρχει ένα d% και γ%.
Αυτό σημαίνει ότι θα προσπαθήσει sscanf σε δεκαδικό int - το% d - και μια χαρα - το γ%.
Για κάθε προσδιοριστή μετατροπή στο format string,
sscanf αναμένει ένα αντίστοιχο επιχείρημα αργότερα στη λίστα επιχείρημα του.
Το επιχείρημα αυτό πρέπει να δείχνει προς μια κατάλληλη τοποθεσία δακτυλογραφημένο
στην οποία αποθηκεύεται το αποτέλεσμα της μετατροπής.
>> Ο συνήθης τρόπος για να γίνει αυτό είναι να δημιουργήσετε μια μεταβλητή στη στοίβα πριν την κλήση sscanf
για κάθε στοιχείο που θέλετε να αναλύσει από τη σειρά
και στη συνέχεια χρησιμοποιήστε τον τελεστή διεύθυνσης - το εμπορικό και - για να περάσει δείκτες
σε αυτές τις μεταβλητές στην κλήση sscanf.
Μπορείτε να δείτε ότι σε GetInt κάνουμε ακριβώς αυτό.
Λίγο πριν την κλήση sscanf, δηλώνουμε έναν int n ονομάζεται και ένα char c κλήση στη στοίβα,
και περνάμε δείκτες τους στην κλήση sscanf.
Κάνοντας αυτές τις μεταβλητές στη στοίβα είναι προτιμότερη από τη χρήση διατεθεί χώρος
στο σωρό με malloc, αφού μπορείτε να αποφύγετε την επιβάρυνση της κλήσης malloc,
και δεν έχετε να ανησυχείτε για διαρροή μνήμης.
Χαρακτήρες που δεν προτάσσεται από το σύμβολο τοις εκατό δεν ζητήσει τη μετατροπή.
Μάλλον το μόνο που προσθέτουν στην προδιαγραφή της μορφής.
>> Για παράδειγμα, εάν η συμβολοσειρά μορφοποίησης σε GetInt ήταν μια ά% αντί,
sscanf θα δούμε για την επιστολή μιας ακολουθείται από μια int,
και ενώ θα επιχειρήσει να μετατρέψει το int, δεν θα κάνει τίποτα άλλο με το ένα.
Η μόνη εξαίρεση σε αυτό είναι κενό.
Λευκό χαρακτήρες χώρος στο format string ταιριάζει με κανένα ποσό whitespace -
ακόμη και καθόλου.
Έτσι, γι 'αυτό το σχόλιο αναφέρει, ενδεχομένως, με τους κορυφαίους και / ή κενά διαστήματα.
Έτσι, σε αυτό το σημείο μοιάζει με κλήση sscanf μας θα προσπαθήσει να αναλύσει συμβολοσειρά εισόδου του χρήστη
από τον έλεγχο για πιθανή ηγετικό κενό,
ακολουθούμενο από ένα int που θα μετατραπεί και να αποθηκευτεί στο int μεταβλητή n
ακολουθούμενη από κάποιο ποσό whitespace, και ακολουθείται από ένα χαρακτήρα
αποθηκεύονται στην μεταβλητή γ εξανθρακώματος.
>> Τι γίνεται με την τιμή επιστροφής;
Sscanf θα αναλύσει τη γραμμή εισόδου από την αρχή μέχρι το τέλος,
σταματά όταν φθάνει στο τέλος ή όταν ένα χαρακτήρα στην είσοδο
δεν ταιριάζει με το χαρακτήρα μορφή ή όταν δεν μπορεί να κάνει μια μετατροπή.
Η τιμή επιστροφής είναι χρησιμοποιείται για να ξεχωρίσω όταν σταμάτησε.
Εάν σταματήσει, επειδή έφτασε το τέλος της συμβολοσειράς εισόδου
πριν προβεί σε οποιεσδήποτε μετατροπές και πριν παραλείποντας να ταιριάζουν με τμήμα της συμβολοσειράς μορφής,
τότε η ειδική σταθερά EOF επιστρέφει.
Διαφορετικά, επιστρέφει τον αριθμό των επιτυχημένων μετατροπών,
η οποία θα μπορούσε να είναι 0, 1 ή 2, αφού έχουμε ζητήσει για δύο μετατροπές.
Στην περίπτωση μας, θέλουμε να βεβαιωθείτε ότι ο χρήστης πληκτρολογήσει σε μια int και μόνο έναν int.
>> Έτσι, θέλουμε να επιστρέψουν sscanf 1. Δείτε για ποιο λόγο;
Αν sscanf επέστρεψε 0, τότε δεν έγιναν μετατροπές,
ώστε ο χρήστης πληκτρολογήσει κάτι άλλο εκτός από έναν int στην αρχή της εισόδου.
Εάν sscanf αποδίδει 2, τότε ο χρήστης δεν πληκτρολογήστε σωστά κατά την έναρξη της εισόδου,
αλλά στη συνέχεια πληκτρολογήσει σε κάποια μη-κενό χαρακτήρα μετά
δεδομένου ότι η μετατροπή% γ πέτυχε.
Πω πω, αυτό είναι αρκετά μια μακρά εξήγηση για μία κλήση της συνάρτησης.
Τέλος πάντων, αν θέλετε περισσότερες πληροφορίες σχετικά με sscanf και τα αδέλφια του,
ενημερωθείτε για τις σελίδες man, Google, ή και τα δύο.
Υπάρχουν πολλές επιλογές συμβολοσειρά μορφοποίησης,
και αυτά μπορεί να σας εξοικονομήσει πολλά χειρωνακτική εργασία όταν προσπαθεί να αναλύσει χορδές σε C.
>> Η τελική λειτουργία της βιβλιοθήκης να εξετάσουμε είναι GetString.
Αποδεικνύεται ότι GetString είναι μια δύσκολη λειτουργία για να γράψει σωστά,
ακόμα κι αν φαίνεται σαν ένα τέτοιο απλό, κοινό έργο.
Γιατί συμβαίνει αυτό;
Λοιπόν, ας σκεφτούμε πώς θα πάμε για να αποθηκεύσετε τη γραμμή ότι ο χρήστης πληκτρολογεί μέσα
Δεδομένου ότι ένας συμβολοσειρά είναι μια ακολουθία των χαρακτήρων,
θα μπορούσαμε να θέλουμε να το αποθηκεύσετε σε μια σειρά στη στοίβα,
αλλά θα πρέπει να ξέρετε πόσο καιρό η σειρά θα είναι όταν θα το δηλώσει.
Ομοίως, αν θέλουμε να το βάλετε στο σωρό,
θα πρέπει να περάσει για να malloc τον αριθμό των bytes που θέλουμε να αποθεματικό,
αλλά αυτό είναι αδύνατο.
Δεν έχουμε ιδέα πόσοι χαρακτήρες, ο χρήστης θα πληκτρολογήσετε
πριν ο χρήστης κάνει πραγματικότητα τις πληκτρολογείτε.
>> Ένας αφελής λύση σε αυτό το πρόβλημα είναι να διατηρήσει μόνο ένα μεγάλο κομμάτι του χώρου, ας πούμε,
ένα μπλοκ των 1000 χαρακτήρες για την είσοδο του χρήστη,
υποθέτοντας ότι ο χρήστης δεν θα πρέπει να πληκτρολογήσετε σε μια σειρά τόσο πολύ.
Αυτό είναι μια κακή ιδέα για δύο λόγους.
Πρώτον, με την παραδοχή ότι οι χρήστες συνήθως δεν πληκτρολογήσετε χορδές τόσο πολύ,
θα μπορούσατε να χάνουμε πολύ μνήμη.
Με σύγχρονα μηχανήματα, αυτό μπορεί να μην είναι ένα ζήτημα, αν το κάνετε αυτό
σε μία ή δύο μεμονωμένες περιπτώσεις,
αλλά εάν παίρνετε είσοδο του χρήστη σε ένα βρόχο και την αποθήκευση για μελλοντική χρήση,
μπορείτε γρήγορα να ρουφήξει έναν τόνο της μνήμης.
Επιπλέον, αν το πρόγραμμα που γράφεις είναι για ένα μικρότερο υπολογιστή -
μια συσκευή όπως ένα smartphone ή κάτι άλλο με περιορισμένη μνήμη -
αυτή η λύση θα προκαλέσει προβλήματα πολύ πιο γρήγορα.
Η δεύτερη, πιο σοβαρός λόγος να μην το κάνουμε αυτό είναι ότι αφήνει το πρόγραμμά σας ευάλωτο
σε αυτό που ονομάζεται μια επίθεση υπερχείλισης buffer.
Στον προγραμματισμό, ένα ρυθμιστικό είναι η μνήμη που χρησιμοποιείται για την προσωρινή αποθήκευση εισόδου ή εξόδου δεδομένων,
που στην προκειμένη περίπτωση είναι 1000-char μπλοκ μας.
Μία υπερχείλιση συμβαίνει όταν δεδομένα γράφονται πέρα ​​από το τέλος του μπλοκ.
>> Για παράδειγμα, εάν ένας χρήστης κάνει πραγματικά τύπο σε περισσότερα από 1000 χαρακτήρες.
Μπορεί να έχουν δοκιμάσει αυτό το λάθος κατά τον προγραμματισμό με συστοιχίες.
Αν έχετε μια σειρά από 10 ints, τίποτα δεν σας σταματά από το να προσπαθούν να διαβάσουν ή να γράψουν
η 15η int.
Δεν υπάρχουν προειδοποιήσεις ή σφάλματα μεταγλώττισης.
Το πρόγραμμα μόλις γκάφες ευθεία και από τη μνήμη
όπου πιστεύει ότι η 15η int θα είναι, και αυτό μπορεί να αντικαταστήσει άλλες μεταβλητές σας.
Στη χειρότερη περίπτωση, μπορείτε να αντικαταστήσετε κάποια από εσωτερικό πρόγραμμα σας
μηχανισμούς ελέγχου, με αποτέλεσμα το πρόγραμμα να εκτελέσει πραγματικά διαφορετικές οδηγίες
από ό, τι προβλεπόταν.
>> Τώρα, δεν είναι κοινή για να γίνει αυτό κατά λάθος,
αλλά αυτό είναι μια αρκετά συνηθισμένη τεχνική που χρησιμοποιούν κακούς να σπάσει τα προγράμματα
και να θέσει κακόβουλο κώδικα στους υπολογιστές άλλων ανθρώπων.
Ως εκ τούτου, δεν μπορούμε να χρησιμοποιήσουμε μόνο αφελής λύση μας.
Χρειαζόμαστε έναν τρόπο να αποτρέψει τα προγράμματά μας από το να είναι ευάλωτες
σε μια επίθεση υπερχείλισης buffer.
Για να το κάνετε αυτό, θα πρέπει να βεβαιωθείτε ότι το ρυθμιστικό μας μπορούν να αναπτυχθούν όπως θα διαβάσετε
περισσότερα στοιχεία από το χρήστη.
Η λύση; Χρησιμοποιούμε ένα ρυθμιστικό διέθεσε σωρό.
Από τη στιγμή να αλλάξετε το μέγεθος χρησιμοποιώντας το resize τη λειτουργία realloc,
και να παρακολουθείτε δύο αριθμούς - το δείκτη του επόμενου κενή υποδοχή στο ρυθμιστικό
και το μήκος ή την ικανότητα του ρυθμιστικού διαλύματος.
Διαβάζουμε σε χαρακτήρες από το χρήστη, ένα κάθε φορά, χρησιμοποιώντας τον fgetc λειτουργία.
Το επιχείρημα της fgetc λειτουργία παίρνει - stdin - είναι μια αναφορά στο πρότυπο συμβολοσειρά εισόδου,
το οποίο είναι ένα προσυνδεδεμένο κανάλι εισόδου που χρησιμοποιείται για τη μεταφορά είσοδο του χρήστη
από το τερματικό προς το πρόγραμμα.
>> Κάθε φορά που ο χρήστης πληκτρολογεί σε ένα νέο χαρακτήρα, ελέγχουμε να δούμε αν ο δείκτης
της επόμενης ελεύθερη υποδοχή συν 1 είναι μεγαλύτερη από τη χωρητικότητα του ρυθμιστικού.
Το ένα έρχεται σε γιατί αν το επόμενο δωρεάν δείκτη είναι 5,
τότε το μήκος ρυθμιστικό μας πρέπει να είναι 6 έως 0, χάρη ευρετηρίαση.
Αν έχουμε εξαντληθεί ο χώρος στο buffer, τότε προσπαθούμε να αλλάξετε το μέγεθός του,
διπλασιάζοντας έτσι ώστε να μειώσουμε τον αριθμό των φορών που το μέγεθος
αν ο χρήστης πληκτρολογεί σε μια πραγματικά μακρά σειρά.
Εάν η σειρά έχει πάρει πάρα πολύ καιρό ή αν θα ξεμείνει από μνήμη σωρού,
να απελευθερώσουμε ρυθμιστικό μας και μηδενική απόδοση.
>> Τέλος, έχουμε προσαρτήσει την απανθρακώματος στο ρυθμιστικό διάλυμα.
Μόλις τα χτυπήματα χρήστη να εισάγει ή να επιστρέψουν, σηματοδοτώντας μια νέα γραμμή,
ή το ειδικό χαρα - τον έλεγχο d - η οποία σηματοδοτεί το τέλος της εισόδου,
κάνουμε έναν έλεγχο για να δει αν ο χρήστης πληκτρολογήσει πραγματικά σε οτιδήποτε.
Αν όχι, θα επιστρέψει null.
Διαφορετικά, γιατί ρυθμιστικό μας είναι ίσως μεγαλύτερο από ό, τι χρειαζόμαστε,
στη χειρότερη περίπτωση είναι σχεδόν διπλάσια χρειαζόμαστε
διπλασιαστεί από τη στιγμή που κάθε φορά που το μέγεθος,
κάνουμε ένα νέο αντίγραφο του string χρησιμοποιώντας μόνο το μέγεθος του χώρου που χρειαζόμαστε.
Έχουμε προσθέσει ένα επιπλέον 1 έως την κλήση malloc,
έτσι ώστε να υπάρχει χώρος για τον ειδικό χαρακτήρα null τερματισμού - το \ 0,
η οποία θα επισυνάπτει στην σειρά όταν θα αντιγράψετε το υπόλοιπο των χαρακτήρων,
χρησιμοποιώντας strncpy αντί του strcpy
έτσι ώστε να μπορούμε να καθορίσουμε ακριβώς πόσα χαρακτήρες που θέλετε να αντιγράψετε.
Strcpy αντιγράφει μέχρι να χτυπήσει μια \ 0.
Στη συνέχεια, θα ελευθερώσει ρυθμιστικό μας και επιστρέφει το αντίτυπο στον καλούντα.
>> Ποιος ήξερε ένα τέτοιο απλό φαινομενικά λειτουργία θα μπορούσε να είναι τόσο περίπλοκο;
Τώρα ξέρετε τι συμβαίνει στη βιβλιοθήκη CS50.
>> Το όνομά μου είναι Nate Hardison, και αυτό είναι CS50.
[CS50.TV]