1 00:00:00,000 --> 00:00:02,490 [Powered by Google Translate] [CS50 Βιβλιοθήκη] 2 00:00:02,490 --> 00:00:04,220 [Nate Hardison] [Πανεπιστήμιο του Χάρβαρντ] 3 00:00:04,220 --> 00:00:07,260 [Αυτό είναι CS50. CS50.TV] 4 00:00:07,260 --> 00:00:11,510 Η βιβλιοθήκη CS50 είναι ένα χρήσιμο εργαλείο που έχουμε εγκαταστήσει στη συσκευή 5 00:00:11,510 --> 00:00:15,870 ώστε να είναι ευκολότερο για σας να γράψετε προγράμματα που ζητούν από τους χρήστες για την είσοδο. 6 00:00:15,870 --> 00:00:21,670 Σε αυτό το βίντεο, θα τραβήξει την κουρτίνα και να δούμε τι ακριβώς είναι το CS50 βιβλιοθήκη. 7 00:00:21,670 --> 00:00:25,520 >> Στο βίντεο για βιβλιοθήκες C, μιλάμε για το πώς θα περιλαμβάνουν # κεφαλίδες αρχεία 8 00:00:25,520 --> 00:00:27,570 της βιβλιοθήκης στον πηγαίο κώδικα σας, 9 00:00:27,570 --> 00:00:31,150 και στη συνέχεια να συνδεθεί με ένα δυαδικό αρχείο της βιβλιοθήκης κατά τη διάρκεια της σύνδεσης φάση 10 00:00:31,150 --> 00:00:33,140 της διαδικασίας κατάρτισης. 11 00:00:33,140 --> 00:00:36,440 Τα αρχεία κεφαλίδας καθορίσετε τη διασύνδεση της βιβλιοθήκης. 12 00:00:36,440 --> 00:00:41,280 Δηλαδή, λεπτομερώς όλους τους πόρους που η βιβλιοθήκη έχει στη διάθεσή της για να το χρησιμοποιήσετε, 13 00:00:41,280 --> 00:00:45,250 όπως οι δηλώσεις λειτουργία, σταθερές και τύπους δεδομένων. 14 00:00:45,250 --> 00:00:48,890 Το δυαδικό αρχείο βιβλιοθήκης περιέχει την εφαρμογή της βιβλιοθήκης, 15 00:00:48,890 --> 00:00:54,580 η οποία έχει συνταχθεί από τα αρχεία κεφαλίδας της βιβλιοθήκης και της βιβλιοθήκης. γ. αρχεία πηγαίου κώδικα. 16 00:00:54,580 --> 00:00:59,820 >> Το δυαδικό αρχείο της βιβλιοθήκης δεν είναι πολύ ενδιαφέρον να δούμε δεδομένου ότι είναι, επίσης, σε δυαδικό. 17 00:00:59,820 --> 00:01:03,300 Έτσι, ας ρίξουμε μια ματιά στα αρχεία κεφαλίδας για τη βιβλιοθήκη αντ 'αυτού. 18 00:01:03,300 --> 00:01:07,710 Σε αυτή την περίπτωση, υπάρχει μόνο ένα αρχείο κεφαλίδας που ονομάζεται cs50.h. 19 00:01:07,710 --> 00:01:11,040 Έχουμε εγκαταστήσει στο χρήστη περιλαμβάνουν κατάλογο 20 00:01:11,040 --> 00:01:15,150 μαζί με τα αρχεία επικεφαλίδων των άλλων βιβλιοθηκών του συστήματος ». 21 00:01:15,150 --> 00:01:21,530 >> Ένα από τα πρώτα πράγματα που θα παρατηρήσετε είναι ότι περιλαμβάνει cs50.h # header αρχεία από άλλες βιβλιοθήκες - 22 00:01:21,530 --> 00:01:25,670 float, όρια, bool πρότυπο, πρότυπο και lib. 23 00:01:25,670 --> 00:01:28,800 Και πάλι, μετά από την αρχή του δεν ανακαλύπτουμε τον τροχό, 24 00:01:28,800 --> 00:01:33,490 έχουμε χτίσει την CS0 βιβλιοθήκη χρησιμοποιώντας τα εργαλεία που παρέχονται για άλλα μας. 25 00:01:33,490 --> 00:01:38,690 >> Το επόμενο πράγμα που θα δείτε στη βιβλιοθήκη είναι ότι ορίζουμε ένα νέο είδος που ονομάζεται "string". 26 00:01:38,690 --> 00:01:42,330 Αυτή η γραμμή δημιουργεί πραγματικά ακριβώς ένα ψευδώνυμο για τον τύπο char *, 27 00:01:42,330 --> 00:01:46,000 έτσι δεν εμπνέει μαγικά το νέο τύπο string με χαρακτηριστικά 28 00:01:46,000 --> 00:01:49,650 συνήθως συνδέεται με αντικείμενα εγχόρδων σε άλλες γλώσσες, 29 00:01:49,650 --> 00:01:50,850 όπως το μήκος. 30 00:01:50,850 --> 00:01:55,180 Ο λόγος που έχουμε κάνει είναι να προστατεύσει νέα προγραμματιστές από τις φρικιαστικές λεπτομέρειες 31 00:01:55,180 --> 00:01:57,580 των δεικτών, έως ότου είστε έτοιμοι. 32 00:01:57,580 --> 00:02:00,130 >> Το επόμενο μέρος του αρχείου κεφαλίδας είναι η δήλωση των λειτουργιών 33 00:02:00,130 --> 00:02:04,410 ότι η CS50 βιβλιοθήκη παρέχει μαζί με την τεκμηρίωση. 34 00:02:04,410 --> 00:02:06,940 Παρατηρήστε το επίπεδο της λεπτομέρειας στα σχόλια εδώ. 35 00:02:06,940 --> 00:02:10,560 Αυτό είναι εξαιρετικά σημαντικό, έτσι ώστε οι άνθρωποι ξέρουν πώς να χρησιμοποιούν αυτές τις λειτουργίες. 36 00:02:10,560 --> 00:02:19,150 Δηλώνουμε, με τη σειρά του, να λειτουργεί ζητήσει από το χρήστη και χαρακτήρες επιστροφής, δίκλινα, πλωτήρες, ints, 37 00:02:19,150 --> 00:02:24,160 πολύ λαχταρά, και έγχορδα, χρησιμοποιώντας το δικό μας τύπο string. 38 00:02:24,160 --> 00:02:26,260 Σύμφωνα με την αρχή της απόκρυψης πληροφοριών, 39 00:02:26,260 --> 00:02:31,640 έχουμε θέσει τον ορισμό μας σε ένα ξεχωριστό αρχείο εφαρμογής c -. cs50.c-- 40 00:02:31,640 --> 00:02:35,110 βρίσκεται στον πηγαίο κατάλογο του χρήστη. 41 00:02:35,110 --> 00:02:38,040 Έχουμε υπό την προϋπόθεση ότι το αρχείο ώστε να μπορείτε να ρίξετε μια ματιά σε αυτό, 42 00:02:38,040 --> 00:02:41,490 να μάθουν από αυτό, και το μεταγλωττίσετε σε διαφορετικές μηχανές, αν θέλετε, 43 00:02:41,490 --> 00:02:45,510 παρόλο που πιστεύω ότι είναι καλύτερα να εργαστούν για τη συσκευή για αυτή την κατηγορία. 44 00:02:45,510 --> 00:02:47,580 Τέλος πάντων, ας ρίξουμε μια ματιά σε αυτό τώρα. 45 00:02:49,020 --> 00:02:54,620 >> Οι λειτουργίες getchar, GetDouble, GetFloat, GetInt, και GetLongLong 46 00:02:54,620 --> 00:02:58,160 είναι όλα χτισμένα στην κορυφή της GetString λειτουργία. 47 00:02:58,160 --> 00:03:01,510 Αποδεικνύεται ότι ουσιαστικά όλοι ακολουθούν το ίδιο μοτίβο. 48 00:03:01,510 --> 00:03:04,870 Χρησιμοποιούν ένα βρόχο while να ζητήσει από το χρήστη για μία γραμμή εισόδου. 49 00:03:04,870 --> 00:03:08,430 Επιστρέφουν μια ιδιαίτερη αξία αν ο χρήστης εισάγει μια κενή γραμμή. 50 00:03:08,430 --> 00:03:11,750 Προσπαθούν να αναλύσει είσοδο του χρήστη ως τον κατάλληλο τύπο, 51 00:03:11,750 --> 00:03:15,010 είτε πρόκειται για ένα char, ένα διπλό, ένα float, κλπ. 52 00:03:15,010 --> 00:03:18,710 Και τότε θα επιστρέψουν είτε το αποτέλεσμα αν η είσοδος με επιτυχία αναλύονται 53 00:03:18,710 --> 00:03:21,330 ή μπορούν reprompt το χρήστη. 54 00:03:21,330 --> 00:03:24,230 >> Σε υψηλό επίπεδο, δεν υπάρχει τίποτα πραγματικά δύσκολο εδώ. 55 00:03:24,230 --> 00:03:28,760 Μπορεί να έχετε γράψει τον εαυτό σας με παρόμοια δομή κώδικα στο παρελθόν. 56 00:03:28,760 --> 00:03:34,720 Ίσως το πιο αινιγματικό μέλλον είναι το μέρος sscanf κλήση που αναλύει είσοδο του χρήστη. 57 00:03:34,720 --> 00:03:38,160 Sscanf είναι μέρος της οικογένειας με τη μορφή μετατροπής εισόδου. 58 00:03:38,160 --> 00:03:42,300 Ζει σε io.h πρότυπο, και η δουλειά του είναι να αναλύσει μια σειρά C, 59 00:03:42,300 --> 00:03:46,520 σύμφωνα με μια συγκεκριμένη μορφή, η αποθήκευση των αποτελεσμάτων μεταγλώττιση στη μεταβλητή 60 00:03:46,520 --> 00:03:48,720 που παρέχεται από τον καλούντα. 61 00:03:48,720 --> 00:03:53,570 Δεδομένου ότι οι λειτουργίες μετατροπής μορφή εισόδου είναι πολύ χρήσιμα, ευρέως χρησιμοποιούμενες λειτουργίες 62 00:03:53,570 --> 00:03:56,160 που δεν είναι σούπερ διαισθητική κατά την πρώτη, 63 00:03:56,160 --> 00:03:58,300 θα πάμε πέρα ​​από το πώς λειτουργεί sscanf. 64 00:03:58,300 --> 00:04:03,330 >> Το πρώτο επιχείρημα είναι να sscanf ένα char * - ένας δείκτης σε χαρακτήρα. 65 00:04:03,330 --> 00:04:05,150 Για τη λειτουργία να λειτουργήσει σωστά, 66 00:04:05,150 --> 00:04:08,340 ότι ο χαρακτήρας θα πρέπει να είναι ο πρώτος χαρακτήρας της σειράς C, 67 00:04:08,340 --> 00:04:12,270 τερματίζεται με το null \ 0 χαρακτήρας. 68 00:04:12,270 --> 00:04:15,120 Αυτή είναι η σειρά να αναλύσει 69 00:04:15,120 --> 00:04:18,269 Το δεύτερο επιχείρημα για sscanf είναι μια συμβολοσειρά μορφής, 70 00:04:18,269 --> 00:04:20,839 συνήθως πέρασε ως σταθερή σειρά, 71 00:04:20,839 --> 00:04:24,040 και μπορεί να έχετε δει μια σειρά, όπως αυτό πριν, όταν χρησιμοποιεί το printf. 72 00:04:24,040 --> 00:04:28,650 Ένα σημάδι τοις εκατό στη σειρά σχήμα δείχνει έναν προσδιοριστή μετατροπής. 73 00:04:28,650 --> 00:04:30,850 Ο χαρακτήρας αμέσως μετά το σύμβολο του ποσοστού, 74 00:04:30,850 --> 00:04:35,430 δηλώνει ο τύπος C που θέλουμε sscanf να μετατρέψετε σε. 75 00:04:35,430 --> 00:04:40,090 Σε GetInt, θα δείτε ότι υπάρχει ένα d% και γ%. 76 00:04:40,090 --> 00:04:48,690 Αυτό σημαίνει ότι θα προσπαθήσει sscanf σε δεκαδικό int - το% d - και μια χαρα - το γ%. 77 00:04:48,690 --> 00:04:51,510 Για κάθε προσδιοριστή μετατροπή στο format string, 78 00:04:51,510 --> 00:04:56,620 sscanf αναμένει ένα αντίστοιχο επιχείρημα αργότερα στη λίστα επιχείρημα του. 79 00:04:56,620 --> 00:05:00,850 Το επιχείρημα αυτό πρέπει να δείχνει προς μια κατάλληλη τοποθεσία δακτυλογραφημένο 80 00:05:00,850 --> 00:05:04,000 στην οποία αποθηκεύεται το αποτέλεσμα της μετατροπής. 81 00:05:04,000 --> 00:05:08,910 >> Ο συνήθης τρόπος για να γίνει αυτό είναι να δημιουργήσετε μια μεταβλητή στη στοίβα πριν την κλήση sscanf 82 00:05:08,910 --> 00:05:11,440 για κάθε στοιχείο που θέλετε να αναλύσει από τη σειρά 83 00:05:11,440 --> 00:05:15,520 και στη συνέχεια χρησιμοποιήστε τον τελεστή διεύθυνσης - το εμπορικό και - για να περάσει δείκτες 84 00:05:15,520 --> 00:05:19,100 σε αυτές τις μεταβλητές στην κλήση sscanf. 85 00:05:19,100 --> 00:05:22,720 Μπορείτε να δείτε ότι σε GetInt κάνουμε ακριβώς αυτό. 86 00:05:22,720 --> 00:05:28,240 Λίγο πριν την κλήση sscanf, δηλώνουμε έναν int n ονομάζεται και ένα char c κλήση στη στοίβα, 87 00:05:28,240 --> 00:05:32,340 και περνάμε δείκτες τους στην κλήση sscanf. 88 00:05:32,340 --> 00:05:35,800 Κάνοντας αυτές τις μεταβλητές στη στοίβα είναι προτιμότερη από τη χρήση διατεθεί χώρος 89 00:05:35,800 --> 00:05:39,350 στο σωρό με malloc, αφού μπορείτε να αποφύγετε την επιβάρυνση της κλήσης malloc, 90 00:05:39,350 --> 00:05:43,060 και δεν έχετε να ανησυχείτε για διαρροή μνήμης. 91 00:05:43,060 --> 00:05:47,280 Χαρακτήρες που δεν προτάσσεται από το σύμβολο τοις εκατό δεν ζητήσει τη μετατροπή. 92 00:05:47,280 --> 00:05:50,380 Μάλλον το μόνο που προσθέτουν στην προδιαγραφή της μορφής. 93 00:05:50,380 --> 00:05:56,500 >> Για παράδειγμα, εάν η συμβολοσειρά μορφοποίησης σε GetInt ήταν μια ά% αντί, 94 00:05:56,500 --> 00:05:59,800 sscanf θα δούμε για την επιστολή μιας ακολουθείται από μια int, 95 00:05:59,800 --> 00:06:04,360 και ενώ θα επιχειρήσει να μετατρέψει το int, δεν θα κάνει τίποτα άλλο με το ένα. 96 00:06:04,360 --> 00:06:07,440 Η μόνη εξαίρεση σε αυτό είναι κενό. 97 00:06:07,440 --> 00:06:11,030 Λευκό χαρακτήρες χώρος στο format string ταιριάζει με κανένα ποσό whitespace - 98 00:06:11,030 --> 00:06:12,890 ακόμη και καθόλου. 99 00:06:12,890 --> 00:06:18,100 Έτσι, γι 'αυτό το σχόλιο αναφέρει, ενδεχομένως, με τους κορυφαίους και / ή κενά διαστήματα. 100 00:06:18,100 --> 00:06:22,910 Έτσι, σε αυτό το σημείο μοιάζει με κλήση sscanf μας θα προσπαθήσει να αναλύσει συμβολοσειρά εισόδου του χρήστη 101 00:06:22,910 --> 00:06:25,380 από τον έλεγχο για πιθανή ηγετικό κενό, 102 00:06:25,380 --> 00:06:29,300 ακολουθούμενο από ένα int που θα μετατραπεί και να αποθηκευτεί στο int μεταβλητή n 103 00:06:29,300 --> 00:06:33,090 ακολουθούμενη από κάποιο ποσό whitespace, και ακολουθείται από ένα χαρακτήρα 104 00:06:33,090 --> 00:06:35,810 αποθηκεύονται στην μεταβλητή γ εξανθρακώματος. 105 00:06:35,810 --> 00:06:37,790 >> Τι γίνεται με την τιμή επιστροφής; 106 00:06:37,790 --> 00:06:41,560 Sscanf θα αναλύσει τη γραμμή εισόδου από την αρχή μέχρι το τέλος, 107 00:06:41,560 --> 00:06:44,860 σταματά όταν φθάνει στο τέλος ή όταν ένα χαρακτήρα στην είσοδο 108 00:06:44,860 --> 00:06:49,320 δεν ταιριάζει με το χαρακτήρα μορφή ή όταν δεν μπορεί να κάνει μια μετατροπή. 109 00:06:49,320 --> 00:06:52,690 Η τιμή επιστροφής είναι χρησιμοποιείται για να ξεχωρίσω όταν σταμάτησε. 110 00:06:52,690 --> 00:06:55,670 Εάν σταματήσει, επειδή έφτασε το τέλος της συμβολοσειράς εισόδου 111 00:06:55,670 --> 00:07:00,630 πριν προβεί σε οποιεσδήποτε μετατροπές και πριν παραλείποντας να ταιριάζουν με τμήμα της συμβολοσειράς μορφής, 112 00:07:00,630 --> 00:07:04,840 τότε η ειδική σταθερά EOF επιστρέφει. 113 00:07:04,840 --> 00:07:08,200 Διαφορετικά, επιστρέφει τον αριθμό των επιτυχημένων μετατροπών, 114 00:07:08,200 --> 00:07:14,380 η οποία θα μπορούσε να είναι 0, 1 ή 2, αφού έχουμε ζητήσει για δύο μετατροπές. 115 00:07:14,380 --> 00:07:19,000 Στην περίπτωση μας, θέλουμε να βεβαιωθείτε ότι ο χρήστης πληκτρολογήσει σε μια int και μόνο έναν int. 116 00:07:19,000 --> 00:07:23,370 >> Έτσι, θέλουμε να επιστρέψουν sscanf 1. Δείτε για ποιο λόγο; 117 00:07:23,370 --> 00:07:26,850 Αν sscanf επέστρεψε 0, τότε δεν έγιναν μετατροπές, 118 00:07:26,850 --> 00:07:31,690 ώστε ο χρήστης πληκτρολογήσει κάτι άλλο εκτός από έναν int στην αρχή της εισόδου. 119 00:07:31,690 --> 00:07:37,100 Εάν sscanf αποδίδει 2, τότε ο χρήστης δεν πληκτρολογήστε σωστά κατά την έναρξη της εισόδου, 120 00:07:37,100 --> 00:07:41,390 αλλά στη συνέχεια πληκτρολογήσει σε κάποια μη-κενό χαρακτήρα μετά 121 00:07:41,390 --> 00:07:44,940 δεδομένου ότι η μετατροπή% γ πέτυχε. 122 00:07:44,940 --> 00:07:49,570 Πω πω, αυτό είναι αρκετά μια μακρά εξήγηση για μία κλήση της συνάρτησης. 123 00:07:49,570 --> 00:07:53,460 Τέλος πάντων, αν θέλετε περισσότερες πληροφορίες σχετικά με sscanf και τα αδέλφια του, 124 00:07:53,460 --> 00:07:57,130 ενημερωθείτε για τις σελίδες man, Google, ή και τα δύο. 125 00:07:57,130 --> 00:07:58,780 Υπάρχουν πολλές επιλογές συμβολοσειρά μορφοποίησης, 126 00:07:58,780 --> 00:08:03,830 και αυτά μπορεί να σας εξοικονομήσει πολλά χειρωνακτική εργασία όταν προσπαθεί να αναλύσει χορδές σε C. 127 00:08:03,830 --> 00:08:07,180 >> Η τελική λειτουργία της βιβλιοθήκης να εξετάσουμε είναι GetString. 128 00:08:07,180 --> 00:08:10,310 Αποδεικνύεται ότι GetString είναι μια δύσκολη λειτουργία για να γράψει σωστά, 129 00:08:10,310 --> 00:08:14,290 ακόμα κι αν φαίνεται σαν ένα τέτοιο απλό, κοινό έργο. 130 00:08:14,290 --> 00:08:16,170 Γιατί συμβαίνει αυτό; 131 00:08:16,170 --> 00:08:21,380 Λοιπόν, ας σκεφτούμε πώς θα πάμε για να αποθηκεύσετε τη γραμμή ότι ο χρήστης πληκτρολογεί μέσα 132 00:08:21,380 --> 00:08:23,880 Δεδομένου ότι ένας συμβολοσειρά είναι μια ακολουθία των χαρακτήρων, 133 00:08:23,880 --> 00:08:26,430 θα μπορούσαμε να θέλουμε να το αποθηκεύσετε σε μια σειρά στη στοίβα, 134 00:08:26,430 --> 00:08:31,250 αλλά θα πρέπει να ξέρετε πόσο καιρό η σειρά θα είναι όταν θα το δηλώσει. 135 00:08:31,250 --> 00:08:34,030 Ομοίως, αν θέλουμε να το βάλετε στο σωρό, 136 00:08:34,030 --> 00:08:38,090 θα πρέπει να περάσει για να malloc τον αριθμό των bytes που θέλουμε να αποθεματικό, 137 00:08:38,090 --> 00:08:39,730 αλλά αυτό είναι αδύνατο. 138 00:08:39,730 --> 00:08:42,760 Δεν έχουμε ιδέα πόσοι χαρακτήρες, ο χρήστης θα πληκτρολογήσετε 139 00:08:42,760 --> 00:08:46,590 πριν ο χρήστης κάνει πραγματικότητα τις πληκτρολογείτε. 140 00:08:46,590 --> 00:08:50,720 >> Ένας αφελής λύση σε αυτό το πρόβλημα είναι να διατηρήσει μόνο ένα μεγάλο κομμάτι του χώρου, ας πούμε, 141 00:08:50,720 --> 00:08:54,540 ένα μπλοκ των 1000 χαρακτήρες για την είσοδο του χρήστη, 142 00:08:54,540 --> 00:08:57,980 υποθέτοντας ότι ο χρήστης δεν θα πρέπει να πληκτρολογήσετε σε μια σειρά τόσο πολύ. 143 00:08:57,980 --> 00:09:00,810 Αυτό είναι μια κακή ιδέα για δύο λόγους. 144 00:09:00,810 --> 00:09:05,280 Πρώτον, με την παραδοχή ότι οι χρήστες συνήθως δεν πληκτρολογήσετε χορδές τόσο πολύ, 145 00:09:05,280 --> 00:09:07,610 θα μπορούσατε να χάνουμε πολύ μνήμη. 146 00:09:07,610 --> 00:09:10,530 Με σύγχρονα μηχανήματα, αυτό μπορεί να μην είναι ένα ζήτημα, αν το κάνετε αυτό 147 00:09:10,530 --> 00:09:13,890 σε μία ή δύο μεμονωμένες περιπτώσεις, 148 00:09:13,890 --> 00:09:17,630 αλλά εάν παίρνετε είσοδο του χρήστη σε ένα βρόχο και την αποθήκευση για μελλοντική χρήση, 149 00:09:17,630 --> 00:09:20,870 μπορείτε γρήγορα να ρουφήξει έναν τόνο της μνήμης. 150 00:09:20,870 --> 00:09:24,450 Επιπλέον, αν το πρόγραμμα που γράφεις είναι για ένα μικρότερο υπολογιστή - 151 00:09:24,450 --> 00:09:28,100 μια συσκευή όπως ένα smartphone ή κάτι άλλο με περιορισμένη μνήμη - 152 00:09:28,100 --> 00:09:32,060 αυτή η λύση θα προκαλέσει προβλήματα πολύ πιο γρήγορα. 153 00:09:32,060 --> 00:09:36,450 Η δεύτερη, πιο σοβαρός λόγος να μην το κάνουμε αυτό είναι ότι αφήνει το πρόγραμμά σας ευάλωτο 154 00:09:36,450 --> 00:09:39,710 σε αυτό που ονομάζεται μια επίθεση υπερχείλισης buffer. 155 00:09:39,710 --> 00:09:45,840 Στον προγραμματισμό, ένα ρυθμιστικό είναι η μνήμη που χρησιμοποιείται για την προσωρινή αποθήκευση εισόδου ή εξόδου δεδομένων, 156 00:09:45,840 --> 00:09:48,980 που στην προκειμένη περίπτωση είναι 1000-char μπλοκ μας. 157 00:09:48,980 --> 00:09:53,370 Μία υπερχείλιση συμβαίνει όταν δεδομένα γράφονται πέρα ​​από το τέλος του μπλοκ. 158 00:09:53,370 --> 00:09:57,790 >> Για παράδειγμα, εάν ένας χρήστης κάνει πραγματικά τύπο σε περισσότερα από 1000 χαρακτήρες. 159 00:09:57,790 --> 00:10:01,570 Μπορεί να έχουν δοκιμάσει αυτό το λάθος κατά τον προγραμματισμό με συστοιχίες. 160 00:10:01,570 --> 00:10:05,620 Αν έχετε μια σειρά από 10 ints, τίποτα δεν σας σταματά από το να προσπαθούν να διαβάσουν ή να γράψουν 161 00:10:05,620 --> 00:10:07,810 η 15η int. 162 00:10:07,810 --> 00:10:10,000 Δεν υπάρχουν προειδοποιήσεις ή σφάλματα μεταγλώττισης. 163 00:10:10,000 --> 00:10:13,250 Το πρόγραμμα μόλις γκάφες ευθεία και από τη μνήμη 164 00:10:13,250 --> 00:10:18,150 όπου πιστεύει ότι η 15η int θα είναι, και αυτό μπορεί να αντικαταστήσει άλλες μεταβλητές σας. 165 00:10:18,150 --> 00:10:22,040 Στη χειρότερη περίπτωση, μπορείτε να αντικαταστήσετε κάποια από εσωτερικό πρόγραμμα σας 166 00:10:22,040 --> 00:10:26,820 μηχανισμούς ελέγχου, με αποτέλεσμα το πρόγραμμα να εκτελέσει πραγματικά διαφορετικές οδηγίες 167 00:10:26,820 --> 00:10:28,340 από ό, τι προβλεπόταν. 168 00:10:28,340 --> 00:10:31,360 >> Τώρα, δεν είναι κοινή για να γίνει αυτό κατά λάθος, 169 00:10:31,360 --> 00:10:35,150 αλλά αυτό είναι μια αρκετά συνηθισμένη τεχνική που χρησιμοποιούν κακούς να σπάσει τα προγράμματα 170 00:10:35,150 --> 00:10:39,080 και να θέσει κακόβουλο κώδικα στους υπολογιστές άλλων ανθρώπων. 171 00:10:39,080 --> 00:10:42,910 Ως εκ τούτου, δεν μπορούμε να χρησιμοποιήσουμε μόνο αφελής λύση μας. 172 00:10:42,910 --> 00:10:45,590 Χρειαζόμαστε έναν τρόπο να αποτρέψει τα προγράμματά μας από το να είναι ευάλωτες 173 00:10:45,590 --> 00:10:47,880 σε μια επίθεση υπερχείλισης buffer. 174 00:10:47,880 --> 00:10:51,430 Για να το κάνετε αυτό, θα πρέπει να βεβαιωθείτε ότι το ρυθμιστικό μας μπορούν να αναπτυχθούν όπως θα διαβάσετε 175 00:10:51,430 --> 00:10:53,850 περισσότερα στοιχεία από το χρήστη. 176 00:10:53,850 --> 00:10:57,440 Η λύση; Χρησιμοποιούμε ένα ρυθμιστικό διέθεσε σωρό. 177 00:10:57,440 --> 00:10:59,950 Από τη στιγμή να αλλάξετε το μέγεθος χρησιμοποιώντας το resize τη λειτουργία realloc, 178 00:10:59,950 --> 00:11:04,580 και να παρακολουθείτε δύο αριθμούς - το δείκτη του επόμενου κενή υποδοχή στο ρυθμιστικό 179 00:11:04,580 --> 00:11:08,390 και το μήκος ή την ικανότητα του ρυθμιστικού διαλύματος. 180 00:11:08,390 --> 00:11:13,210 Διαβάζουμε σε χαρακτήρες από το χρήστη, ένα κάθε φορά, χρησιμοποιώντας τον fgetc λειτουργία. 181 00:11:13,210 --> 00:11:19,360 Το επιχείρημα της fgetc λειτουργία παίρνει - stdin - είναι μια αναφορά στο πρότυπο συμβολοσειρά εισόδου, 182 00:11:19,360 --> 00:11:23,810 το οποίο είναι ένα προσυνδεδεμένο κανάλι εισόδου που χρησιμοποιείται για τη μεταφορά είσοδο του χρήστη 183 00:11:23,810 --> 00:11:26,270 από το τερματικό προς το πρόγραμμα. 184 00:11:26,270 --> 00:11:29,890 >> Κάθε φορά που ο χρήστης πληκτρολογεί σε ένα νέο χαρακτήρα, ελέγχουμε να δούμε αν ο δείκτης 185 00:11:29,890 --> 00:11:35,810 της επόμενης ελεύθερη υποδοχή συν 1 είναι μεγαλύτερη από τη χωρητικότητα του ρυθμιστικού. 186 00:11:35,810 --> 00:11:39,690 Το ένα έρχεται σε γιατί αν το επόμενο δωρεάν δείκτη είναι 5, 187 00:11:39,690 --> 00:11:44,150 τότε το μήκος ρυθμιστικό μας πρέπει να είναι 6 έως 0, χάρη ευρετηρίαση. 188 00:11:44,150 --> 00:11:48,350 Αν έχουμε εξαντληθεί ο χώρος στο buffer, τότε προσπαθούμε να αλλάξετε το μέγεθός του, 189 00:11:48,350 --> 00:11:51,690 διπλασιάζοντας έτσι ώστε να μειώσουμε τον αριθμό των φορών που το μέγεθος 190 00:11:51,690 --> 00:11:54,760 αν ο χρήστης πληκτρολογεί σε μια πραγματικά μακρά σειρά. 191 00:11:54,760 --> 00:11:57,950 Εάν η σειρά έχει πάρει πάρα πολύ καιρό ή αν θα ξεμείνει από μνήμη σωρού, 192 00:11:57,950 --> 00:12:01,350 να απελευθερώσουμε ρυθμιστικό μας και μηδενική απόδοση. 193 00:12:01,350 --> 00:12:04,170 >> Τέλος, έχουμε προσαρτήσει την απανθρακώματος στο ρυθμιστικό διάλυμα. 194 00:12:04,170 --> 00:12:08,200 Μόλις τα χτυπήματα χρήστη να εισάγει ή να επιστρέψουν, σηματοδοτώντας μια νέα γραμμή, 195 00:12:08,200 --> 00:12:12,050 ή το ειδικό χαρα - τον έλεγχο d - η οποία σηματοδοτεί το τέλος της εισόδου, 196 00:12:12,050 --> 00:12:16,240 κάνουμε έναν έλεγχο για να δει αν ο χρήστης πληκτρολογήσει πραγματικά σε οτιδήποτε. 197 00:12:16,240 --> 00:12:18,820 Αν όχι, θα επιστρέψει null. 198 00:12:18,820 --> 00:12:22,280 Διαφορετικά, γιατί ρυθμιστικό μας είναι ίσως μεγαλύτερο από ό, τι χρειαζόμαστε, 199 00:12:22,280 --> 00:12:24,830 στη χειρότερη περίπτωση είναι σχεδόν διπλάσια χρειαζόμαστε 200 00:12:24,830 --> 00:12:27,830 διπλασιαστεί από τη στιγμή που κάθε φορά που το μέγεθος, 201 00:12:27,830 --> 00:12:31,840 κάνουμε ένα νέο αντίγραφο του string χρησιμοποιώντας μόνο το μέγεθος του χώρου που χρειαζόμαστε. 202 00:12:31,840 --> 00:12:34,220 Έχουμε προσθέσει ένα επιπλέον 1 έως την κλήση malloc, 203 00:12:34,220 --> 00:12:37,810 έτσι ώστε να υπάρχει χώρος για τον ειδικό χαρακτήρα null τερματισμού - το \ 0, 204 00:12:37,810 --> 00:12:41,990 η οποία θα επισυνάπτει στην σειρά όταν θα αντιγράψετε το υπόλοιπο των χαρακτήρων, 205 00:12:41,990 --> 00:12:45,060 χρησιμοποιώντας strncpy αντί του strcpy 206 00:12:45,060 --> 00:12:48,830 έτσι ώστε να μπορούμε να καθορίσουμε ακριβώς πόσα χαρακτήρες που θέλετε να αντιγράψετε. 207 00:12:48,830 --> 00:12:51,690 Strcpy αντιγράφει μέχρι να χτυπήσει μια \ 0. 208 00:12:51,690 --> 00:12:55,740 Στη συνέχεια, θα ελευθερώσει ρυθμιστικό μας και επιστρέφει το αντίτυπο στον καλούντα. 209 00:12:55,740 --> 00:12:59,840 >> Ποιος ήξερε ένα τέτοιο απλό φαινομενικά λειτουργία θα μπορούσε να είναι τόσο περίπλοκο; 210 00:12:59,840 --> 00:13:02,820 Τώρα ξέρετε τι συμβαίνει στη βιβλιοθήκη CS50. 211 00:13:02,820 --> 00:13:06,470 >> Το όνομά μου είναι Nate Hardison, και αυτό είναι CS50. 212 00:13:06,470 --> 00:13:08,350 [CS50.TV]