1 00:00:00,000 --> 00:00:02,500 [Powered by Google Translate] [סעיף 5 - יותר נוח] 2 00:00:02,500 --> 00:00:04,690 [רוב אודן - אוניברסיטת הרווארד] 3 00:00:04,690 --> 00:00:07,250 [זה CS50. - CS50.TV] 4 00:00:08,990 --> 00:00:14,250 >> כמו שאמרתי בדוא"ל שלי, יש הרבה דברים שאתה יכול להשתמש 5 00:00:14,250 --> 00:00:17,060 מלבד המכשיר בעצם לעשות את הערכות הבעייתיות. 6 00:00:17,060 --> 00:00:19,910 אנו ממליצים לך לעשות את זה במכשיר רק בגלל שאז אנחנו יכולים בקלות רבה יותר לסייע לך 7 00:00:19,910 --> 00:00:22,070 ואנחנו יודעים איך הכל הולכים לעבודה. 8 00:00:22,070 --> 00:00:26,950 אבל כדוגמה אחת שבו אתה יכול לעשות דברים אם, למשל, אין לך גישה 9 00:00:26,950 --> 00:00:31,570 למכשיר או שאתה רוצה לעבוד במרתף מרכז המדע - 10 00:00:31,570 --> 00:00:33,090 שבעצם יש להם את המכשיר מדי - 11 00:00:33,090 --> 00:00:35,150 אם אתה רוצה לעבוד בכל מקום. 12 00:00:35,150 --> 00:00:42,370 דוגמה אחת היא האם ראה / שמעת על SSH? 13 00:00:44,380 --> 00:00:47,780 SSH הוא בעצם בדיוק כמו להתחבר למשהו. 14 00:00:47,780 --> 00:00:51,340 למעשה, כרגע אני SSHed לתוך המכשיר. 15 00:00:51,340 --> 00:00:54,290 אני לא עובד ישירות במכשיר. 16 00:00:55,930 --> 00:01:01,060 הנה המכשיר, ואם אתה מסתכל פה אתה רואה את כתובת ה-IP. 17 00:01:01,060 --> 00:01:03,650 אני לא אעבוד במכשיר עצמו; 18 00:01:03,650 --> 00:01:08,840 אני תמיד בא אל חלון / מסוף חלון iTerm2. 19 00:01:08,840 --> 00:01:15,910 אתה יכול SSH שלכתובת ה-IP, jharvard@192.168.129.128 ssh. 20 00:01:15,910 --> 00:01:20,390 אני זוכר את המספר הזה בקלות רבה בגלל שזה דפוס כזה נחמד. 21 00:01:20,390 --> 00:01:24,920 אבל שתשאל אותי לסיסמה שלי, ועכשיו אני במכשיר. 22 00:01:24,920 --> 00:01:33,060 בעיקרון, בשלב זה, אם נפתח הטרמינל הפנימי של המכשיר עצמו, 23 00:01:33,060 --> 00:01:36,350 ממשק זה, אבל אתה משתמש בו, הוא בדיוק אותו הדבר 24 00:01:36,350 --> 00:01:40,010 כממשק אני משתמש כאן, אבל עכשיו אתה SSHed. 25 00:01:42,240 --> 00:01:44,920 אתה לא צריך SSH למכשיר. 26 00:01:44,920 --> 00:01:52,360 דוגמה אחת למקום אחר אתה יכול SSH להיא שאני די בטוח שיש לך כברירת מחדל - 27 00:01:52,360 --> 00:01:55,020 אה. גדול יותר. 28 00:01:55,020 --> 00:02:01,130 כולכם צריכים להיות על ידי חשבונות FAS ברירת המחדל בשרתי FAS. 29 00:02:01,130 --> 00:02:06,840 עבורי, הייתי SSH לrbowden@nice.fas.harvard.edu. 30 00:02:06,840 --> 00:02:11,610 זה הולך לשאול אותך, כי בפעם הראשונה, ואתה אומר כן. 31 00:02:11,610 --> 00:02:15,840 הסיסמה שלי היא רק הולכת להיות הסיסמה של FAS שלי. 32 00:02:15,840 --> 00:02:22,650 ועכשיו, אני SSHed לשרתים הנחמדים, ואני יכול לעשות מה שאני רוצה כאן. 33 00:02:22,650 --> 00:02:28,560 הרבה שיעורים אתה עלול לקחת, כמו 124, הולכים להיות לך להעלות את דברים לכאן 34 00:02:28,560 --> 00:02:30,950 למעשה להגיש סטי הבעיה שלך. 35 00:02:30,950 --> 00:02:34,100 אבל אומר שאין לך גישה למכשיר שלך. 36 00:02:34,100 --> 00:02:37,910 ואז אתה יכול לעשות דברים, כמו כאן זה אומר - 37 00:02:37,910 --> 00:02:42,160 זה רק בחלק שלנו של שאלות. 38 00:02:42,160 --> 00:02:45,070 זה יבקש ממך לעשות את זה במכשיר. 39 00:02:45,070 --> 00:02:47,790 במקום זה אני פשוט אעשה את זה בשרת. 40 00:02:47,790 --> 00:02:50,560 אני הולך לפתוח את זה. 41 00:02:50,560 --> 00:02:55,670 הבעיה הולכת להיות שאתה רגיל להשתמש במשהו כמו gedit 42 00:02:55,670 --> 00:02:58,160 או מה שבתוך המכשיר. 43 00:02:58,160 --> 00:03:01,830 אתה לא הולך לקחת את זה על שרת FAS. 44 00:03:01,830 --> 00:03:04,110 זה הכל רק הולך להיות ממשק טקסטואלי זה. 45 00:03:04,110 --> 00:03:09,180 אז אתה יכול גם אחד, לנסות ללמוד עורך טקסט שיש להם. 46 00:03:09,180 --> 00:03:12,130 יש להם ננו. 47 00:03:12,130 --> 00:03:14,990 ננו הוא בדרך כלל די קל לשימוש. 48 00:03:14,990 --> 00:03:19,470 אתה יכול להשתמש בחצים שלך והקלד כרגיל. 49 00:03:19,470 --> 00:03:21,250 אז זה לא קשה. 50 00:03:21,250 --> 00:03:24,720 אם אתה רוצה להגיע ממש מפואר שתוכל להשתמש Emacs, 51 00:03:24,720 --> 00:03:29,850 שאני כנראה לא היה צריך לפתוח, כי אני אפילו לא יודע איך לסגור את Emacs. 52 00:03:29,850 --> 00:03:32,760 הבקרה X, C בקרה? כן. 53 00:03:32,760 --> 00:03:35,310 או שאתה יכול להשתמש Vim, וזה מה שאני משתמש. 54 00:03:35,310 --> 00:03:37,800 ולכן אלה הם האפשרויות שלך. 55 00:03:37,800 --> 00:03:43,830 אם אתה לא רוצה לעשות את זה, אתה גם יכול, אם אתה מסתכל על manual.cs50.net-- 56 00:03:43,830 --> 00:03:45,410 אה. 57 00:03:45,410 --> 00:03:49,920 במחשב, אתה יכול SSH באמצעות שפכטל, 58 00:03:49,920 --> 00:03:51,940 שאתה הולך צריך להוריד בנפרד. 59 00:03:51,940 --> 00:03:55,460 במקינטוש, אתה יכול פשוט על ידי שימוש במסוף ברירת מחדל, או שאתה יכול להוריד iTerm2, 60 00:03:55,460 --> 00:03:58,490 שזה כמו מסוף יפה, מפואר. 61 00:03:58,490 --> 00:04:03,780 אם אתה הולך לmanual.cs50.net תראה קישור לNotepad + +, 62 00:04:03,780 --> 00:04:07,120 וזה מה שאתה יכול להשתמש במחשב אישי. 63 00:04:07,120 --> 00:04:13,340 זה מאפשר לך SFTP מNotepad + +, שהוא בעצם SSH. 64 00:04:13,340 --> 00:04:17,750 מה זה ייתן לך לעשות הוא לערוך את הקבצים שלך באופן מקומי, 65 00:04:17,750 --> 00:04:20,670 ואז כל פעם שאתה רוצה לשמור אותם, זה יחסוך לnice.fas, 66 00:04:20,670 --> 00:04:23,670 איפה אתה יכול גם להפעיל אותם. 67 00:04:23,670 --> 00:04:26,880 והמקביל במקינטוש הולך להיות TextWrangler. 68 00:04:26,880 --> 00:04:28,760 אז זה מאפשר לך לעשות את אותו דבר. 69 00:04:28,760 --> 00:04:32,800 זה מאפשר לך לערוך קבצים באופן מקומי ולשמור אותם לnice.fas, 70 00:04:32,800 --> 00:04:35,730 איפה אתה יכול גם להפעיל אותם. 71 00:04:35,730 --> 00:04:40,400 אז אם אתה אי פעם נתקע בלי מכשיר, יש לך אפשרויות אלה 72 00:04:40,400 --> 00:04:44,230 עדיין לעשות סטי הבעיה שלך. 73 00:04:44,230 --> 00:04:48,250 הבעיה אחת הוא הולך להיות שאתה לא הולך לספרייה יש CS50 74 00:04:48,250 --> 00:04:51,580 בגלל nice.fas לא כברירת מחדל יש את זה. 75 00:04:51,580 --> 00:04:55,970 אתה יכול גם להוריד את ספריית CS50 - 76 00:04:55,970 --> 00:04:58,470 אני לא חושב שאני צריך את זה בשלב זה. 77 00:04:58,470 --> 00:05:03,270 אתה יכול גם להוריד את ספריית CS50 ולהעתיק אותו לnice.fas, 78 00:05:03,270 --> 00:05:07,450 או שאני חושב בשלב זה אנחנו לא משתמשים בזה יותר בכל מקרה. 79 00:05:07,450 --> 00:05:12,720 ואם כן, אתה יכול לעת עתה להחליף אותו 80 00:05:12,720 --> 00:05:18,480 היישומים של הפונקציות בCS50 ספרייה בכל מקרה. 81 00:05:18,480 --> 00:05:21,370 כך שלא צריך להיות שהרבה מהגבלה. 82 00:05:21,370 --> 00:05:23,710 וזהו זה. 83 00:05:26,460 --> 00:05:29,820 >> אני אחזור למכשיר עכשיו, יצטרך לעשות הכל במכשיר. 84 00:05:29,820 --> 00:05:37,510 כאשר מסתכלים על הקטע של שאלות שלנו, בהתחלה, כמו שאמרתי בדוא"ל שלי, 85 00:05:37,510 --> 00:05:43,620 יש לנו על מה לדבר אחד קצר שהייתם אמור לצפות. 86 00:05:43,620 --> 00:05:51,980 יש לנו את הפניית & צינורות ועל שלוש שאלות הבאות. 87 00:05:51,980 --> 00:05:56,070 >> לאיזה זרם אל פונקציות כמו printf לכתוב כברירת מחדל? 88 00:05:56,070 --> 00:05:59,130 אז זרם. מהו זרם? 89 00:06:06,520 --> 00:06:15,100 זרם הוא בעצם כמו שזה רק חלק - 90 00:06:15,100 --> 00:06:21,450 זה אפילו לא מקור 1s ו 0s. 91 00:06:21,450 --> 00:06:24,920 הזרם זה כמו לבקש כאן הוא פלט סטנדרטי. 92 00:06:24,920 --> 00:06:27,250 ויצאתי כל כך סטנדרטי הוא זרם שכשאתה כותב אליו, 93 00:06:27,250 --> 00:06:30,940 הוא מופיע על המסך. 94 00:06:30,940 --> 00:06:36,860 את התקן, על ידי זרם, זה אומר שאתה פשוט כותב 1s ו 0s אליו, 95 00:06:36,860 --> 00:06:40,220 והקצה השני של את התקן פשוט קורא שמהנחל. 96 00:06:40,220 --> 00:06:43,540 זה רק מחרוזת של 1s ו 0s. 97 00:06:43,540 --> 00:06:45,570 אתה יכול לכתוב לזרמים או שאתה יכול לקרוא מזרמים 98 00:06:45,570 --> 00:06:47,950 תלוי מה הוא למעשה זרם. 99 00:06:47,950 --> 00:06:52,800 שני הזרמים האחרים כברירת המחדל הם סטנדרטיים ובשגיאה סטנדרטית. 100 00:06:52,800 --> 00:06:57,540 תקן הוא בכל פעם שאתה GetString, זה מחכה לך לחומר הזנה. 101 00:06:57,540 --> 00:07:01,570 אז זה מחכה לך, זה ממש מחכה בסטנדרטי ב, 102 00:07:01,570 --> 00:07:04,880 וזה באמת מה שאתה מקבל בעת ההקלדה במקלדת. 103 00:07:04,880 --> 00:07:07,530 אתה מקליד לתוך סטנדרטי פנימה 104 00:07:07,530 --> 00:07:10,050 שגיאה סטנדרטית היא בעצם שווה ערך לפלט סטנדרטי, 105 00:07:10,050 --> 00:07:13,280 אבל זה שהתמחה בעת הדפסה לשגיאה סטנדרטית, 106 00:07:13,280 --> 00:07:16,770 אתה אמור להדפיס הודעות שגיאה היחידה ש 107 00:07:16,770 --> 00:07:20,200 כדי שתוכל להבחין בין ההודעות הרגילות המודפסות למסך 108 00:07:20,200 --> 00:07:24,560 לעומת הודעות שגיאה תלויות אם הם הלכו לפלט סטנדרטי או שגיאה סטנדרטית. 109 00:07:24,560 --> 00:07:28,660 קבצים גם כן. 110 00:07:28,660 --> 00:07:32,440 יצאו רגיל, סטנדרטי ובטעות התקן הם פשוט זרמים מיוחדים, 111 00:07:32,440 --> 00:07:36,810 אבל באמת כל קובץ, בעת פתיחת קובץ, הוא הופך לזרם של בתים 112 00:07:36,810 --> 00:07:40,740 שבו אתה יכול פשוט לקרוא שמהנחל. 113 00:07:40,740 --> 00:07:47,770 אתה, על פי רוב, ניתן רק לחשוב על קובץ כזרם של בתים. 114 00:07:47,770 --> 00:07:51,190 אז זרמים מה שהם כותבים לברירת מחדל? פלט סטנדרטי. 115 00:07:51,190 --> 00:07:56,980 >> מה ההבדל בין> ו? >> 116 00:07:58,140 --> 00:08:03,710 האם מישהו לראות את הווידאו מראש? אוקיי. 117 00:08:03,710 --> 00:08:10,960 > הולך להיות איך אתה להפנות לקבצים, 118 00:08:10,960 --> 00:08:15,240 ו>> גם הולך לניתוב פלט לקבצים, 119 00:08:15,240 --> 00:08:17,820 אבל זה קורה במקום לצרף לקובץ. 120 00:08:17,820 --> 00:08:23,430 לדוגמה, תניח שיש בי dict ממש כאן, 121 00:08:23,430 --> 00:08:27,020 ורק דברים הפנימיים של dict הוא חתול, חתול, כלב, דגים, כלב. 122 00:08:27,020 --> 00:08:31,530 פקודה אחת שיש לך בשורת הפקודה היא חתול, 123 00:08:31,530 --> 00:08:34,539 שרק הולך להדפיס מה שיש בקובץ. 124 00:08:34,539 --> 00:08:40,679 לכן, כאשר אני אומר dict חתול, זה הולך להדפיס חתול, חתול, כלב, דגים, כלב. זה כל מה שהחתול עושה. 125 00:08:40,679 --> 00:08:46,280 זה אומר שזה מודפס לסטנדרטי את החתול, חתול, כלב, דגים, כלב. 126 00:08:46,280 --> 00:08:53,240 אם אני במקום שרצונך לנתב מחדש לקובץ, אני יכול להשתמש> ולהפנות אותו לכל הקובץ. 127 00:08:53,240 --> 00:08:56,460 אני אתקשר אל קובץ הקובץ. 128 00:08:56,460 --> 00:09:00,320 אז עכשיו אם אני ls, אני אראה שיש לי קובץ חדש בשם קובץ. 129 00:09:00,320 --> 00:09:05,700 ואם אני פותח אותו, זה הולך להיות בדיוק מה שהחתול לשים בשורת הפקודה. 130 00:09:05,700 --> 00:09:11,040 אז עכשיו אם אני עושה את זה שוב, ואז זה הולך להפנות את הפלט לקובץ, 131 00:09:11,040 --> 00:09:13,930 ואני הולך לקבל את אותו הדבר בדיוק. 132 00:09:13,930 --> 00:09:17,910 אז מבחינה טכנית, זה בטל לגמרי את מה שהיה לנו. 133 00:09:17,910 --> 00:09:22,970 ונראים אם אני משנה dict, הוצאתי את הכלב. 134 00:09:22,970 --> 00:09:29,980 עכשיו אם dict לתוך קובץ שהחתול שוב, אנחנו הולכים לתת את הגרסה החדשה עם הכלב הוסר. 135 00:09:29,980 --> 00:09:32,400 אז זה עוקף אותה לחלוטין. 136 00:09:32,400 --> 00:09:36,640 במקום זאת, אם אנו משתמשים >>, זה הולך לצרף קובץ. 137 00:09:36,640 --> 00:09:40,860 כעת, פתיחת קובץ, שאנו רואים שיש לנו בדיוק אותו הדבר נדפס פעמים 138 00:09:40,860 --> 00:09:44,920 כי זה היה שם פעם אחת, ולאחר מכן צרפנו אל המקור. 139 00:09:44,920 --> 00:09:48,130 אז זה מה ש> ו>> לעשות. 140 00:09:48,130 --> 00:09:50,580 האם הפעם הבאה תשאלנה - הוא אינו שואל על זה. 141 00:09:50,580 --> 00:09:59,050 >> האחד האחר שיש לנו הוא <, שאם> מפנה את התקן, 142 00:09:59,050 --> 00:10:01,970 <הולך להיות סטנדרטי להפנות פנימה 143 00:10:01,970 --> 00:10:12,050 בואו נראים אם יש לנו דוגמה. 144 00:10:14,750 --> 00:10:16,930 אני יכול לכתוב אחד מהיר אמיתי. 145 00:10:17,870 --> 00:10:25,700 בואו ניקח כל קובץ, hello.c. 146 00:10:56,060 --> 00:10:59,070 קובץ פשוט יחסית. 147 00:10:59,070 --> 00:11:03,570 אני מקבל רק מחרוזת ולאחר מכן להדפיס "שלום" כל מה שאני רק נכנסתי למחרוזת הייתה. 148 00:11:03,570 --> 00:11:07,990 אז לעשות שלום ואחרי. / שלום. 149 00:11:07,990 --> 00:11:10,720 עכשיו זה מעודד אותי להיכנס למשהו, 150 00:11:10,720 --> 00:11:15,070 מה שאומר שהיא מחכה על דברים שנכנסו פנימה סטנדרטי 151 00:11:15,070 --> 00:11:20,450 אז מה שאני רוצה להיכנס לסטנדרטי פנימה אנחנו פשוט הולכים להגיד שלום, רוב! 152 00:11:20,450 --> 00:11:23,310 אז זה מדפיס את התקן שלום, רוב! 153 00:11:23,310 --> 00:11:28,860 אם אני עושה. / שלום ולאחר מכן כוון מחדש, 154 00:11:30,740 --> 00:11:34,310 לעת עתה אתה יכול להפנות רק מקובץ. 155 00:11:34,310 --> 00:11:41,720 אז אם אני שם בקובץ כלשהו, ​​txt, ושמתי את רוב, 156 00:11:41,720 --> 00:11:52,300 אם נגמר לי שלום ואז להפנות לקובץ txt. / הלו, זה הולך לומר שלום, רוב! באופן מיידי. 157 00:11:52,300 --> 00:11:57,160 כשזה יגיע ראשון GetString והיא ממתינה בתקן ב, 158 00:11:57,160 --> 00:12:01,730 הסטנדרטי בהוא כבר לא מחכה במקלדת לנתונים כדי לקבל הזנה. 159 00:12:01,730 --> 00:12:05,980 במקום זאת, יש לנו מנותב הסטנדרטי בלקרוא מקובץ txt. 160 00:12:05,980 --> 00:12:10,290 וכך זה הולך לקרוא מקובץ txt, שהוא רק הקו רוב, 161 00:12:10,290 --> 00:12:13,380 ואז זה הולך להדפיס שלום, רוב! 162 00:12:13,380 --> 00:12:18,180 ואם אני רוצה, אני יכול גם לעשות. / שלום 00:12:21,500 ולאחר מכן בתקן כי דפוס זה, שהוא שלום, רוב!, 164 00:12:21,500 --> 00:12:24,700 אני יכול להפנות את זה לקובץ משלה. 165 00:12:24,700 --> 00:12:29,790 אני אתקשר לקובץ שלום - לא, אני לא אלך, כי זה ההפעלה - txt2. 166 00:12:29,790 --> 00:12:40,150 עכשיו, txt2 הולך להיות הפלט של. / שלום 00:12:43,520 >> שאלות? 168 00:12:45,900 --> 00:12:49,090 >> אוקיי. אז כאן יש לנו צינור. 169 00:12:49,090 --> 00:12:53,510 פייפס הוא היחידה האחרונה של ניתוב מחדש. 170 00:12:53,510 --> 00:12:58,750 >> אה. אני מניח שיותר יחידה אחת של ניתוב מחדש היא אם במקום> אתה עושה 2>, 171 00:12:58,750 --> 00:13:01,070 זה הפניית שגיאה סטנדרטית. 172 00:13:01,070 --> 00:13:06,280 אז אם משהו הלך לשגיאה סטנדרטית, זה לא ילך הכניס לתוך txt2. 173 00:13:06,280 --> 00:13:12,480 אבל שם לב אם אני עושה 2>, אז זה עדיין מדפיס שלום, רוב! לשורת הפקודה 174 00:13:12,480 --> 00:13:18,600 כי אני רק הפניית שגיאה סטנדרטית, אני לא הפניית פלט סטנדרטי. 175 00:13:18,600 --> 00:13:22,210 שגיאה סטנדרטית ופלט סטנדרטי הם שונים. 176 00:13:24,210 --> 00:13:27,080 אם אתה רוצה באמת לכתוב לשגיאה סטנדרטית, 177 00:13:27,080 --> 00:13:35,080 אז אני יכול לשנות את זה כדי להיות fprintf לstderr. 178 00:13:35,080 --> 00:13:37,850 אז printf, כברירת מחדל, מדפיס לפלט סטנדרטי. 179 00:13:37,850 --> 00:13:41,720 אם אני רוצה להדפיס לשגיאה סטנדרטית באופן ידני, ואז אני צריך להשתמש fprintf 180 00:13:41,720 --> 00:13:45,010 וציין מה שאני רוצה להדפיס. 181 00:13:45,010 --> 00:13:49,720 אם במקום שעשיתי stdout fprintf, אז זה בעצם שווה ערך לprintf. 182 00:13:49,720 --> 00:13:55,530 אבל fprintf לשגיאה סטנדרטית. 183 00:13:57,790 --> 00:14:03,650 אז עכשיו, אם אני להפנות את זה לtxt2, שלום, רוב! עדיין הוא מקבל מודפס בשורת הפקודה 184 00:14:03,650 --> 00:14:08,270 מפני שנעשה מודפס לשגיאה סטנדרטית ואני רק הפניית פלט סטנדרטי. 185 00:14:08,270 --> 00:14:16,420 אם אני עכשיו להפנות שגיאה סטנדרטית, עכשיו זה לא יודפס, וtxt2 הולך להיות שלום, רוב! 186 00:14:16,420 --> 00:14:21,910 אז עכשיו, אתה יכול להדפיס טעויות שלך בפועל לשגיאה סטנדרטית 187 00:14:21,910 --> 00:14:24,720 ולהדפיס את ההודעות הרגילות שלך לפלט סטנדרטי. 188 00:14:24,720 --> 00:14:31,420 ולכן כאשר אתה מפעיל את התכנית שלך, אתה יכול להפעיל אותו באותה מידה. / שלום מסוג זה עם 2> 189 00:14:31,420 --> 00:14:33,800 כך שהתכנית שלך הולכת לרוץ באופן רגיל, 190 00:14:33,800 --> 00:14:38,400 אבל כל הודעות שגיאה שאתה מקבל אתה יכול לבדוק מאוחר יותר ביומן השגיאות שלך, 191 00:14:38,400 --> 00:14:44,500 כך טעויות, ואז לחפש הקובץ מאוחר יותר והטעויות שלך יהיה כל שגיאות שקרו. 192 00:14:45,200 --> 00:14:47,540 >> שאלות? 193 00:14:47,540 --> 00:14:58,070 >> האחרון הוא צינור, שאתה יכול לחשוב עליו כהוצאה סטנדרטית מפקודה אחת 194 00:14:58,070 --> 00:15:01,210 והופך אותו לסטנדרט בשל הפקודה הבאה. 195 00:15:01,210 --> 00:15:05,570 דוגמה כאן היא הד היא דבר שורת פקודה 196 00:15:05,570 --> 00:15:11,840 שרק הולך מהדהדים מה שאני אשים כטענתה. אני לא היה מכניס את הציטוטים. 197 00:15:11,840 --> 00:15:16,150 אקו בלה, בלה, בלה הוא פשוט הולך להדפיס בלה, בלה, בלה. 198 00:15:16,150 --> 00:15:20,600 קודם, כשאמרתי שאני צריך לשים את רוב לקובץ txt 199 00:15:20,600 --> 00:15:28,830 כי אני יכול להפנות את קבצי txt בלבד, במקום, / אם אני חוזר על רוב 200 00:15:28,830 --> 00:15:35,520 ולאחר מכן אותו לתוך צינור. / שלום, שגם לעשות את אותו הסוג של דבר. 201 00:15:35,520 --> 00:15:39,160 זה לוקח את הפלט של פקודה זו, הד רוב, 202 00:15:39,160 --> 00:15:43,610 ומשתמש בו כקלט ל. / שלום. 203 00:15:44,790 --> 00:15:49,560 אתה יכול לחשוב על זה כלהפנות 1 הד רוב לקובץ 204 00:15:49,560 --> 00:15:54,160 ואז קלט לתוך קובץ. / שלום שזה היה סתם בoutputted. 205 00:15:54,160 --> 00:15:57,850 אבל זה לוקח את הקובץ הזמני מחוץ לתמונה. 206 00:16:01,890 --> 00:16:04,460 >> שאלות על זה? 207 00:16:04,460 --> 00:16:07,150 >> השאלה הבאה הולכת לערב זה. 208 00:16:07,150 --> 00:16:15,310 מה אתה יכול להשתמש בצינור כדי למצוא את מספר השמות ייחודיים בקובץ שנקרא names.txt? 209 00:16:15,310 --> 00:16:24,160 הפקודות שאנחנו הולכים רוצים להשתמש כאן הן ייחודיים, ולכן uniq, ולאחר מכן ב"ש. 210 00:16:24,160 --> 00:16:28,840 אתה יכול לעשות uniq אדם ממש להסתכל על מה שעושה, 211 00:16:28,840 --> 00:16:34,840 וזה רק הולך לסינון שורות תואמות סמוכות מהקלט. 212 00:16:34,840 --> 00:16:40,690 והאיש wc הולך להדפיס, מילת השורה החדשה, וספירת בתים עבור כל קובץ. 213 00:16:40,690 --> 00:16:43,760 והאחרון שאנחנו הולכים רוצים להשתמש הוא סוג, 214 00:16:43,760 --> 00:16:47,410 שהוא הולך רק כדי למיין שורות של קובץ txt. 215 00:16:47,410 --> 00:16:58,080 אם אני עושה איזה קובץ txt, names.txt, וזה רוב, טומי, יוסף, טומי, יוסף, RJ, רוב, 216 00:16:58,080 --> 00:17:03,910 מה שאני רוצה לעשות כאן הוא למצוא מספר השמות ייחודיים בקובץ זה. 217 00:17:03,910 --> 00:17:08,750 אז מה צריך להיות התשובה? >> [תלמיד] 4. >> כן. 218 00:17:08,750 --> 00:17:13,780 זה צריך להיות 4 מאז רוב, טומי, יוסף, RJ הם השמות הייחודיים רק בקובץ זה. 219 00:17:13,780 --> 00:17:20,180 הצעד הראשון, אם אני פשוט עושה את ספירת מילים בnames.txt, 220 00:17:20,180 --> 00:17:24,290 זה בעצם אומר לי הכל. 221 00:17:24,290 --> 00:17:32,560 זהו למעשה דפוס - בואו נראה, הגבר ב"ש - שורה החדשה, מילים, וספירת בתים. 222 00:17:32,560 --> 00:17:38,270 אם אכפת לי רק על קווים, אז אני יכול רק לעשות names.txt wc-l. 223 00:17:41,730 --> 00:17:44,300 אז זה שלב 1. 224 00:17:44,300 --> 00:17:50,510 אבל אני לא רוצה names.txt wc-l בגלל names.txt פשוט מכיל את כל השמות, 225 00:17:50,510 --> 00:17:54,170 ואני רוצה לסנן את כל אלה שאינם ייחודיים. 226 00:17:54,170 --> 00:18:01,200 אז אם אני עושה names.txt uniq, שלא ממש נותן לי מה שאני רוצה 227 00:18:01,200 --> 00:18:03,760 מכיוון שהשמות הכפולים הם עדיין שם. 228 00:18:03,760 --> 00:18:07,690 מדוע זה כך? למה uniq לא עושה מה שאני רוצה? 229 00:18:07,690 --> 00:18:10,500 [תלמיד] הכפילויות הן [לא נשמע] >> כן. 230 00:18:10,500 --> 00:18:16,370 זכור את הדף לאדם uniq אומר קווי התאמה סמוך סינון. 231 00:18:16,370 --> 00:18:19,680 הם לא צמודים, כך שזה לא יסנן אותם. 232 00:18:19,680 --> 00:18:31,100 אם אני למיין אותם ראשון, names.txt הסוג הולך לשים את כל הקווים הכפולים יחד. 233 00:18:31,100 --> 00:18:34,450 אז עכשיו names.txt המיון הוא ש. 234 00:18:34,450 --> 00:18:40,550 אני הולך רוצה להשתמש בו כקלט לuniq, שהוא | uniq. 235 00:18:40,550 --> 00:18:43,390 זה נותן לי יוסף, RJ, רוב, טומי, 236 00:18:43,390 --> 00:18:49,260 ואני רוצה להשתמש בו כקלט לwc-l, 237 00:18:49,260 --> 00:18:52,740 שהוא הולך לתת לי 4. 238 00:18:52,740 --> 00:18:56,930 כמו שכתוב כאן, מה אתה יכול להשתמש בצינור? 239 00:18:56,930 --> 00:19:01,390 אתה יכול לעשות הרבה דברים כמו באמצעות סדרה של פקודות 240 00:19:01,390 --> 00:19:05,130 שבו אתה משתמש בפלט של פקודה אחת כקלט לפקודה הבאה. 241 00:19:05,130 --> 00:19:08,780 אתה יכול לעשות הרבה דברים, הרבה דברים חכמים. 242 00:19:08,780 --> 00:19:11,440 >> שאלות? 243 00:19:12,910 --> 00:19:14,600 אוקיי. 244 00:19:14,600 --> 00:19:17,880 זהו זה לצינורות וניתוב מחדש. 245 00:19:18,370 --> 00:19:24,090 >> עכשיו אנחנו הולכים על דברים בפועל, חומר הקידוד. 246 00:19:24,090 --> 00:19:29,100 בתוך זה PDF, תראה פקודה זו, 247 00:19:29,100 --> 00:19:32,950 ואתה רוצה להריץ את הפקודה הזו במכשיר שלך. 248 00:19:36,240 --> 00:19:42,250 wget הוא הפקודה רק מקבל משהו מהאינטרנט, בעצם, 249 00:19:42,250 --> 00:19:45,180 כך wget וכתובת אתר זה. 250 00:19:45,180 --> 00:19:49,110 אם אתה נכנסת לכתובת אתר זו בדפדפן שלך, זה יהיה להוריד את הקובץ. 251 00:19:49,110 --> 00:19:52,510 אני פשוט הקלקתי עליו, כך שהוא הוריד את הקובץ בשבילי. 252 00:19:52,510 --> 00:19:55,650 אבל כתיבה של wget שהדבר שבתוך הטרמינל 253 00:19:55,650 --> 00:19:58,620 רק הולך להוריד אותו למסוף שלך. 254 00:19:58,620 --> 00:20:02,750 יש לי section5.zip, ואתה רוצה לפתוח section5.zip, 255 00:20:02,750 --> 00:20:06,520 שהוא הולך לתת לך תיקייה בשם section5, 256 00:20:06,520 --> 00:20:11,550 שהוא הולך להיות כל הקבצים שאנחנו הולכים להיות באמצעות היום בתוכו. 257 00:20:33,380 --> 00:20:37,710 כשמות קבצים של התוכניות אלה מציעים, הם קצת עגלה, 258 00:20:37,710 --> 00:20:40,990 אז המשימה שלך היא להבין מדוע באמצעות gdb. 259 00:20:40,990 --> 00:20:44,560 האם כל מי שיש להם להוריד / יודע איך להגיע אליהם הורדו 260 00:20:44,560 --> 00:20:47,480 למכשיר שלהם? אוקיי. 261 00:20:47,480 --> 00:20:56,400 >> ריצת ./buggy1, זה אומר אשמת פילוח (ליבה זרקה), 262 00:20:56,400 --> 00:21:00,500 שכל פעם שאתה מקבל segfault, זה דבר רע. 263 00:21:00,500 --> 00:21:03,810 באילו נסיבות אתה מקבל segfault? 264 00:21:03,810 --> 00:21:08,210 [תלמיד] ביטול הפנית מצביע null. >> כן. אז זה היא דוגמה אחת. 265 00:21:08,210 --> 00:21:11,580 ביטול הפנית מצביע null אתה הולך לקבל segfault. 266 00:21:11,580 --> 00:21:16,720 מה הוא אמצעי segfault אתה נוגע זיכרון אתה לא צריך להיות נוגע ללב. 267 00:21:16,720 --> 00:21:21,350 אז ביטול הפנית מצביע null נוגע כתובה 0, 268 00:21:21,350 --> 00:21:28,060 ובעצם, כל המחשבים בימים אומרים ש0 כתובת הוא זיכרון אתה לא צריך להיות נוגע ללב. 269 00:21:28,060 --> 00:21:31,920 אז זאת הסיבה לביטול הפנית תוצאות מצביע null בsegfault. 270 00:21:31,920 --> 00:21:37,210 כשאתה במקרה שלא ניתן לאתחל מצביע, אז יש לה ערך זבל, 271 00:21:37,210 --> 00:21:41,520 ולכן כאשר אתה מנסה dereference, ככל הנראה אתה נוגע זיכרון 272 00:21:41,520 --> 00:21:43,540 זה באמצע שום מקום. 273 00:21:43,540 --> 00:21:45,650 אם קורה לך מזל ואת ערך האשפה 274 00:21:45,650 --> 00:21:48,440 קרה להצביע על מקום במחסנית או משהו, 275 00:21:48,440 --> 00:21:50,820 ואז כשאתה dereference שמצביע שבו אתה לא מאותחל, 276 00:21:50,820 --> 00:21:52,730 שום דבר לא ישתבש. 277 00:21:52,730 --> 00:21:55,480 אבל אם זה הוא מצביע, אומר, איפשהו בין הערימה והערימה, 278 00:21:55,480 --> 00:21:59,850 או שזה מצביע בדיוק למקום שלא היה בשימוש על ידי התכנית שלך עדיין, 279 00:21:59,850 --> 00:22:02,240 אז אתה נוגע זיכרון אתה לא צריך לגעת ואתה segfault. 280 00:22:02,240 --> 00:22:06,370 כשאתה כותב פונקציה רקורסיבית וזה הרקורסיה פעמים רבות מדי 281 00:22:06,370 --> 00:22:08,720 והערימה שלך גדלה גדולה מדי ומתנגש המחסנית לתוך דברים 282 00:22:08,720 --> 00:22:12,270 שזה לא צריך להיות התנגשות עם, אתה נוגע זיכרון אתה לא צריך להיות נוגע ללב, 283 00:22:12,270 --> 00:22:14,810 אז אתה segfault. 284 00:22:14,810 --> 00:22:17,010 זה מה segfault הוא. 285 00:22:17,010 --> 00:22:21,810 >> זה גם מאותה הסיבה שאם יש לך מחרוזת כמו - 286 00:22:21,810 --> 00:22:23,930 בואו נחזור לתכנית הקודמת. 287 00:22:23,930 --> 00:22:28,530 בhello.c-אני פשוט הולך לעשות משהו אחר. 288 00:22:28,530 --> 00:22:33,770 char * s = "hello world!"; 289 00:22:33,770 --> 00:22:42,310 אם אני משתמש ב* s = משהו או של [0] = "X"; 290 00:22:42,310 --> 00:22:47,290 עד לשלום,. / שלום, למה שsegfault? 291 00:22:48,410 --> 00:22:51,250 למה זה segfault? 292 00:22:55,660 --> 00:22:57,890 מה היית מצפה שקורה? 293 00:22:57,890 --> 00:23:06,640 אם אני עשיתי printf ("% s \ n", S), מה היית מצפה שיודפס? 294 00:23:06,640 --> 00:23:09,930 [תלמיד] X שלום. >> כן. 295 00:23:09,930 --> 00:23:15,140 הבעיה היא שכאשר אתה מצהיר מחרוזת כמו זה, 296 00:23:15,140 --> 00:23:18,190 זה הוא מצביע שהולך ללכת על הערימה, 297 00:23:18,190 --> 00:23:25,880 ומה זה מצביע על זה הוא מחרוזת הנמצאת בזיכרון לקריאה בלבד. 298 00:23:25,880 --> 00:23:30,560 אז רק בשם הזיכרון, לקריאה בלבד, אתה צריך לקבל את הרעיון 299 00:23:30,560 --> 00:23:33,010 שאם תנסה לשנות את מה שיש בזיכרון לקריאה בלבד, 300 00:23:33,010 --> 00:23:36,670 אתה עושה משהו שאתה לא צריך לעשות עם זיכרון ואתה segfault. 301 00:23:36,670 --> 00:23:45,360 זהו למעשה הבדל גדול בין char * s וchar s []. 302 00:23:45,360 --> 00:23:48,790 אז char s [], עכשיו מחרוזת זה הולכת לשים על הערימה, 303 00:23:48,790 --> 00:23:53,960 והערימה היא לא לקריאה בלבד, מה שאומר שזה אמור לעבוד בסדר גמור. 304 00:23:55,500 --> 00:23:57,370 והוא לא. 305 00:23:57,370 --> 00:24:06,250 זכור שכשאני עושה char * s = "שלום העולם!", של עצמו בערימה 306 00:24:06,250 --> 00:24:10,390 אבל נקודתי s למקום אחר, וכי במקום אחר קורות להיות לקריאה בלבד. 307 00:24:10,390 --> 00:24:15,640 אבל char s [] הוא פשוט משהו במחסנית. 308 00:24:17,560 --> 00:24:21,760 אז זה עוד דוגמה לsegfault קורה. 309 00:24:21,760 --> 00:24:27,820 >> ראה ש./buggy1 הביא segfault. 310 00:24:27,820 --> 00:24:31,810 בתאוריה, אתה לא צריך להסתכל על buggy1.c באופן מיידי. 311 00:24:31,810 --> 00:24:35,170 במקום זאת, אנחנו מסתכלים על זה דרך gdb. 312 00:24:35,170 --> 00:24:37,750 שים לב שכאשר אתה מקבל אשמת פילוח (ליבה זרקה), 313 00:24:37,750 --> 00:24:40,850 אתה מקבל את הקובץ הזה מעל ליבה נקראת כאן. 314 00:24:40,850 --> 00:24:45,200 אם ls-l, נראה שהליבה היא בדרך כלל קובץ די גדול. 315 00:24:45,200 --> 00:24:51,580 זה מספר הבתים של הקובץ, כך שזה נראה כאילו זה קילובייט 250-משהו. 316 00:24:51,580 --> 00:24:56,120 הסיבה לכך היא כי מה שבעצם היא מזבלת הליבה 317 00:24:56,120 --> 00:25:01,410 כאשר תכנית הקריסות שלך, המדינה של זיכרון של התכנית שלך 318 00:25:01,410 --> 00:25:05,230 פשוט מקבל להעתיק ולהדביק לתוך קובץ זה. 319 00:25:05,230 --> 00:25:07,270 זה שהוא מושלך לתוך קובץ. 320 00:25:07,270 --> 00:25:13,060 תכנית זו, בזמן שהוא רץ, קרתה יש שימוש בזיכרון של 250 קילובייט ברחבי, 321 00:25:13,060 --> 00:25:17,040 ואז זה מה שקבל זרק לתוך קובץ זה. 322 00:25:17,040 --> 00:25:23,630 עכשיו אתה יכול להסתכל בקובץ שאם אנחנו עושים ליבת buggy1 gdb. 323 00:25:23,630 --> 00:25:30,130 אנחנו יכולים רק לעשות gdb buggy1, וזה יהיה פשוט להתחיל את gdb באופן קבוע, 324 00:25:30,130 --> 00:25:33,800 באמצעות buggy1 כקובץ הקלט שלה. 325 00:25:33,800 --> 00:25:38,260 אבל אם אתה עושה את ליבת buggy1 gdb, אז זה דווקא הולך להתחיל את gdb 326 00:25:38,260 --> 00:25:40,330 על ידי התבוננות שבקובץ הליבה. 327 00:25:40,330 --> 00:25:45,560 ואתה אומר gdb האמצעי buggy1 יודע שקובץ מגיע מליבת תכנית buggy1. 328 00:25:45,560 --> 00:25:49,580 אז gdb buggy1 הליבה הולכת להביא מייד 329 00:25:49,580 --> 00:25:52,060 לשם התכנית שקרתה לסיים. 330 00:25:57,720 --> 00:26:02,340 אנו רואים כאן תכנית הסתיימה עם 11 אות, אשמת פילוח. 331 00:26:02,340 --> 00:26:10,110 במקרה אנחנו רואים קו ההרכבה, אשר ככל הנראה היא לא מאוד מועיל. 332 00:26:10,110 --> 00:26:15,360 אבל אם תקליד BT או backtrace, שהולך להיות הפונקציה 333 00:26:15,360 --> 00:26:19,430 שנותן לנו את הרשימה של מסגרות המחסנית הנוכחיות שלנו. 334 00:26:19,430 --> 00:26:23,150 אז backtrace. זה נראה כאילו יש לנו שתי מסגרות מחסנית בלבד. 335 00:26:23,150 --> 00:26:26,310 הראשון הוא מסגרת המחסנית הראשית שלנו, 336 00:26:26,310 --> 00:26:29,810 והשני הוא מסגרת המחסנית לפונקציה זו שקורים לך להיות ב, 337 00:26:29,810 --> 00:26:34,440 שנראה כמו שיש לנו את קוד ההרכבה רק ל. 338 00:26:34,440 --> 00:26:38,050 אז בואו נחזור לתפקידו העיקרי שלנו, 339 00:26:38,050 --> 00:26:42,300 כדי לעשות את זה אנחנו יכולים לעשות מסגרת 1, ואני חושב שאנחנו יכולים לעשות גם למטה ו, 340 00:26:42,300 --> 00:26:45,160 אבל אני כמעט אף פעם לא עושה את - או למעלה. כן. 341 00:26:45,160 --> 00:26:50,710 מעלה ומטה. עד שאתה מביא את מסגרת ערימה אחת, את מביא אותך למסגרת מחסנית. 342 00:26:50,710 --> 00:26:53,240 אני נוטה שלא להשתמש בו. 343 00:26:53,240 --> 00:26:59,120 אני רק אומר שדווקא מסגרת 1, אשר עוברת לפריים שהכותרת 1. 344 00:26:59,120 --> 00:27:01,750 1 מסגרת הוא הולך להביא אותנו למסגרת מחסנית ראשית, 345 00:27:01,750 --> 00:27:05,570 וזה כתוב פה שורת הקוד שקורים לך להיות בו. 346 00:27:05,570 --> 00:27:07,950 אם אנחנו רוצים עוד כמה שורות קוד, ניתן לומר רשימה, 347 00:27:07,950 --> 00:27:11,280 וזה הולך לתת לנו את כל השורות של קוד שסביבו. 348 00:27:11,280 --> 00:27:13,360 הקו שאנחנו segfaulted בהיה 6: 349 00:27:13,360 --> 00:27:17,360 if (strcmp ("CS50 סלעים", argv [1]) == 0). 350 00:27:17,360 --> 00:27:24,130 אם זה לא ברור עדיין, אתה יכול לקבל אותו ישר מכאן רק על ידי חשיבה למה זה segfaulted. 351 00:27:24,130 --> 00:27:28,800 אבל אנחנו יכולים לקחת את זה צעד אחד קדימה ואומרים, "למה שargv [1] segfault?" 352 00:27:28,800 --> 00:27:38,830 ההדפסה בואו argv [1], וזה נראה כאילו 0x0 זה, שהוא מצביע null. 353 00:27:38,830 --> 00:27:44,750 אנחנו strcmping CS50 סלעים וnull, ואז זה הולך segfault. 354 00:27:44,750 --> 00:27:48,280 ולמה הוא argv [1] null? 355 00:27:48,640 --> 00:27:51,280 [תלמיד] כי אנחנו לא נותנים לו שום טיעוני שורת פקודה. 356 00:27:51,280 --> 00:27:53,390 כן. אנחנו לא נותנים לו שום טיעוני שורת פקודה. 357 00:27:53,390 --> 00:27:58,460 אז ./buggy1 רק הולך להיות argv [0] יהיה ./buggy1. 358 00:27:58,460 --> 00:28:02,100 זה לא הולך להיות argv [1], כך שהולך segfault. 359 00:28:02,100 --> 00:28:07,450 אבל אם, לעומת זאת, אני עושה רק CS50, זה הולך להגיד אתה מקבל D 360 00:28:07,450 --> 00:28:09,950 כי זה מה שהוא אמור לעשות. 361 00:28:09,950 --> 00:28:15,240 כאשר מסתכלים על buggy1.c, זה אמור להדפיס "אתה מקבל D" - 362 00:28:15,240 --> 00:28:20,820 אם argv [1] לא "CS50 סלעים", "אתה מקבל D", אחר "אתה מקבל!" 363 00:28:20,820 --> 00:28:25,660 אז אם אנחנו רוצים, אנחנו צריכים את זה כדי להשוות כנכון, 364 00:28:25,660 --> 00:28:28,710 מה שאומר שהוא משווה ל 0. 365 00:28:28,710 --> 00:28:31,100 אז argv [1] צריך להיות "CS50 סלעים". 366 00:28:31,100 --> 00:28:35,660 אם אתה רוצה לעשות את זה בשורת הפקודה, אתה צריך להשתמש \ לברוח החלל. 367 00:28:35,660 --> 00:28:41,690 אז CS50 \ סלעים ואתה מקבלים! 368 00:28:41,690 --> 00:28:44,060 אם אתה לא עושה את הקו נטוי, למה זה לא עובד? 369 00:28:44,060 --> 00:28:47,190 [תלמיד] זה שני טיעונים שונים. >> כן. 370 00:28:47,190 --> 00:28:52,540 Argv [1] הולך להיות CS50, וargv [2] הולך להיות סלעים. אוקיי. 371 00:28:52,540 --> 00:28:56,470 >> עכשיו ./buggy2 הולך segfault שוב. 372 00:28:56,470 --> 00:29:01,880 במקום לפתוח אותו עם קובץ הליבה שלה, אנחנו פשוט לפתוח buggy2 ישירות, 373 00:29:01,880 --> 00:29:05,000 כך gdb buggy2. 374 00:29:05,000 --> 00:29:09,590 עכשיו, אם רק להפעיל את התכנית שלנו, אז זה הולך להגיד תכנית קבלה האות SIGSEGV, 375 00:29:09,590 --> 00:29:15,530 אשר segfault אות, וזה המקום שבו קרה לקרות. 376 00:29:15,530 --> 00:29:21,250 כאשר מסתכלים על backtrace שלנו, אנו רואים שאנחנו בoh_no הפונקציה, 377 00:29:21,250 --> 00:29:23,900 שנקרא על ידי dinky הפונקציה, שנקרא על ידי ינקי הפונקציה, 378 00:29:23,900 --> 00:29:26,460 שנקרא על ידי ראשי. 379 00:29:26,460 --> 00:29:31,680 אנחנו יכולים לראות גם את הטענות לפונקציות הללו. 380 00:29:31,680 --> 00:29:34,680 הטיעון לdinky וינקי היה 1. 381 00:29:34,680 --> 00:29:44,390 אם אנו מוסיפים את פונקצית oh_no, אנו רואים כי oh_no פשוט עושה char ** s = NULL; 382 00:29:44,390 --> 00:29:47,410 * של = "בום"; 383 00:29:47,410 --> 00:29:50,330 למה שייכשל? 384 00:29:54,330 --> 00:29:58,380 [תלמיד] אתה לא יכול dereference מצביע null? >> כן. 385 00:29:58,380 --> 00:30:06,090 זה רק אומר שלו ריק, ללא קשר אם זה קורה להיות char **, 386 00:30:06,090 --> 00:30:12,070 אשר, תלוי איך אתה מפרש אותו, זה יכול להיות מצביע למצביע למחרוזת 387 00:30:12,070 --> 00:30:15,550 או מערך של מחרוזות. 388 00:30:15,550 --> 00:30:21,430 זה s הוא NULL, אז * S הוא ביטול הפנית מצביע ריק, 389 00:30:21,430 --> 00:30:24,800 וכך זה הולך לקרוס. 390 00:30:24,800 --> 00:30:27,540 זו אחת הדרכים המהירות ביותר שאתה יכול segfault. 391 00:30:27,540 --> 00:30:31,300 זה פשוט הכרזה בטל ומצביע segfaulting באופן מיידי. 392 00:30:31,300 --> 00:30:34,570 זה מה שהוא עושה oh_no. 393 00:30:34,570 --> 00:30:43,400 אם תלכו עד פריים אחד, אז אנחנו הולכים להיכנס לפונקציה שנקראת oh_no. 394 00:30:43,400 --> 00:30:44,830 אני צריך לעשות את זה. 395 00:30:44,830 --> 00:30:48,610 אם לא יזין את הפקודה ואתה רק על Enter שוב, 396 00:30:48,610 --> 00:30:52,350 זה יהיה פשוט לחזור על הפקודה הקודמת שאתה בורח. 397 00:30:52,350 --> 00:30:56,610 אנחנו נמצאים במסגרת 1. 398 00:30:56,610 --> 00:31:04,650 רישום מסגרת זו, אנו רואים כאן היא הפונקציה שלנו. 399 00:31:04,650 --> 00:31:08,520 אתה יכול להכות שוב ברשימה, או שאתה יכול לעשות רשימה 20 וזה יהיה ברשימה יותר. 400 00:31:08,520 --> 00:31:13,640 Dinky הפונקציה אומר אם אני הוא 1, ואז ללכת לפונקצית oh_no, 401 00:31:13,640 --> 00:31:15,960 שייגש לפונקציה המתגנבת. 402 00:31:15,960 --> 00:31:18,700 ואנחנו יודעים שהוא 1 בגלל שאנחנו לקרות כדי לראות כאן 403 00:31:18,700 --> 00:31:22,560 שdinky נקרא בטענת 1. 404 00:31:22,560 --> 00:31:27,560 או שאתה יכול פשוט להדפיס אני והוא יגיד לי הוא 1. 405 00:31:27,560 --> 00:31:33,770 אנחנו נמצאים היום בהלא מזיקה, ואם אנחנו הולכים עד מסגרת אחרת, אנחנו יודעים שאנחנו בסופו של בינקי. 406 00:31:33,770 --> 00:31:36,600 עד. עכשיו אנחנו בינקי. 407 00:31:36,600 --> 00:31:41,340 רישום פונקציה זו - מהרשימה לפני המחצית קטעה אותי - 408 00:31:41,340 --> 00:31:52,670 זה התחיל כאם אני הוא 0, ואז אנחנו הולכים לקרוא לזה oh_no, אחר קוראים עלוב הזה. 409 00:31:52,670 --> 00:31:57,000 אנחנו יודעים שהייתי 1, אז זה נקרא עלוב הזה. 410 00:31:57,000 --> 00:32:05,030 ועכשיו אנחנו שוב בראשיים, ועיקריים פשוט הולכים להיות אני int = rand ()% 3; 411 00:32:05,030 --> 00:32:08,790 שרק הוא הולך לתת לך מספר אקראי שהוא או 0, 1 או 2. 412 00:32:08,790 --> 00:32:12,780 זה הולך לקרוא בינקי למספר הזה, וזה יחזיר 0. 413 00:32:12,780 --> 00:32:16,700 כאשר מסתכלים על זה, 414 00:32:16,700 --> 00:32:19,880 רק הליכה בתכנית באופן ידני מבלי להפעיל אותו באופן מיידי, 415 00:32:19,880 --> 00:32:25,400 יהיה עליך להגדיר נקודת הפסקה בראשית, מה שאומר שכאשר אנו מפעילים את התכנית 416 00:32:25,400 --> 00:32:31,020 התכנית פועלת עד שהוא פוגע בנקודת הפסקה. 417 00:32:31,020 --> 00:32:35,450 אז הפעלת התכנית, זה יפעל ואז זה הכה את הפונקציה העיקרית ולהפסיק לרוץ. 418 00:32:35,450 --> 00:32:44,700 עכשיו אנחנו בתוך ראשיים, וצעד או הבא הולכים להביא אותנו לשורה הבאה של קוד. 419 00:32:44,700 --> 00:32:47,050 אתה יכול לעשות את צעד או הבא. 420 00:32:47,050 --> 00:32:51,800 להכות הבא, עכשיו אני כבר מוגדר rand ()% 3, כדי שנוכל להדפיס את הערך של i, 421 00:32:51,800 --> 00:32:55,280 והיא אומרת לי היא 1. 422 00:32:55,280 --> 00:32:58,110 עכשיו זה כן משנה אם אנחנו משתמשים באים או צעד. 423 00:32:58,110 --> 00:33:01,000 אני מניח שזה היה חשוב בקודמו, אבל הייתי רוצה להשתמש הבא. 424 00:33:01,000 --> 00:33:06,000 אם אנו משתמשים בשלב, שאנחנו צועדים לפונקציה, מה שאומר שיסתכל על הדבר האמיתי 425 00:33:06,000 --> 00:33:07,940 שקורה בתוך ינקי. 426 00:33:07,940 --> 00:33:10,510 אם אנו משתמשים הבאים, אז זה אומר לעבור על הפונקציה 427 00:33:10,510 --> 00:33:14,070 ופשוט ללכת לשורה הבאה של קוד בפונקציה העיקרית שלנו. 428 00:33:14,070 --> 00:33:17,900 ממש כאן, על הקו הזה, הייתי שבבו אמר rand ()% 3; 429 00:33:17,900 --> 00:33:21,320 אם עשיתי צעד, זה הייתי הולך ליישום רנד 430 00:33:21,320 --> 00:33:25,110 ולהסתכל על מה שקורה שם, ואני יכול לעבור דרך פונקצית רנד. 431 00:33:25,110 --> 00:33:26,920 אבל לא אכפת לי על פונקצית רנד. 432 00:33:26,920 --> 00:33:30,190 אני רק רוצה ללכת לשורה הבאה של קוד בעיקרי, ולכן אני משתמש בא. 433 00:33:30,190 --> 00:33:35,800 אבל עכשיו אכפת לי פונקציה בינקי, אז אני רוצה להיכנס לזה. 434 00:33:35,800 --> 00:33:37,730 עכשיו אני בינקי. 435 00:33:37,730 --> 00:33:42,040 שורת הקוד הראשונה הולכת לומר אם (i == 0), אני לוקח צעד, 436 00:33:42,040 --> 00:33:44,930 אנחנו רואים שבסופו של דבר העלוב הזה. 437 00:33:44,930 --> 00:33:51,620 אם אנחנו, דברי רשימה, אנו רואים שבדקנו היא i = 0. 438 00:33:51,620 --> 00:33:55,470 אני לא שווה 0, אז זה נכנס למצב האחר, 439 00:33:55,470 --> 00:33:59,540 העומד להתקשר dinky (אני). 440 00:33:59,540 --> 00:34:04,030 אתה עלול להתבלבל. 441 00:34:04,030 --> 00:34:07,380 אם אתה רק מסתכל על הקווים האלה באופן ישיר, ייתכן שתחשוב אם (i == 0), 442 00:34:07,380 --> 00:34:10,800 בסדר, אז אני עשיתי צעד ועכשיו אני בdinky (ט), 443 00:34:10,800 --> 00:34:14,120 אתה עשוי לחשוב כי יש אומר שאני = 0 או משהו. 444 00:34:14,120 --> 00:34:18,980 לא, זה רק אומר שהוא יודע שהוא יכול לתקוע ישירות לdinky הקו (אני). 445 00:34:18,980 --> 00:34:23,300 כי אני לא 0, השלב הבא הוא לא הולך להסתיים באחר. 446 00:34:23,300 --> 00:34:26,239 אחר הוא לא קו זה הולך לעצור ב. 447 00:34:26,239 --> 00:34:31,570 זה פשוט הולך לשורה הבאה זה באמת יכול לבצע, שהוא עלוב (אני). 448 00:34:31,570 --> 00:34:36,090 צועדים לתוך dinky (ט), אנו רואים אם (i == 1). 449 00:34:36,090 --> 00:34:42,670 אנחנו יודעים שאני = 1, ולכן כאשר אנו דורכים, אנחנו יודעים שאנחנו הולכים בסופו של oh_no 450 00:34:42,670 --> 00:34:46,489 כי אני = 1 קורא oh_no הפונקציה, שאתה יכול להיכנס אליו, 451 00:34:46,489 --> 00:34:52,969 שהולך להגדיר char ** s = ל NULL ומייד "בום". 452 00:34:54,270 --> 00:34:59,690 ואז באמת מסתכל על יישום buggy2, 453 00:34:59,690 --> 00:35:04,590 זה, אני פשוט מקבל אותו מספר אקראי - 0, 1 או 2 - קורא בינקי, 454 00:35:04,590 --> 00:35:10,610 שאם אני הוא 0 שהיא ממכנת oh_no, אחר היא ממכנת הלא מזיקה, אשר מגיע עד לכאן. 455 00:35:10,610 --> 00:35:18,100 אם אני הוא 1, השיחה oh_no, אחר קוראים חלקלק, שיבואו לכאן, 456 00:35:18,100 --> 00:35:20,460 אם אני הוא 2, מכנה oh_no. 457 00:35:20,460 --> 00:35:24,720 אני אפילו לא חושב שיש דרך - 458 00:35:24,720 --> 00:35:30,030 האם מישהו רואה את הדרך של עשייה זו תכנית שלא segfault? 459 00:35:30,030 --> 00:35:37,530 מפני שאם חסר לי משהו, אם אני הוא 0, אתה segfault באופן מיידי, 460 00:35:37,530 --> 00:35:41,250 אחר אתה הולך לפונקציה שאם אני הוא 1 segfault, 461 00:35:41,250 --> 00:35:44,540 אחר אתה הולך לתפקיד שבו אם אני הוא 2 segfault. 462 00:35:44,540 --> 00:35:46,810 אז לא משנים מה אתה עושה, אתה segfault. 463 00:35:46,810 --> 00:35:52,380 >> אני מניח שדרך אחת של תיקון זה יהיה במקום לעשות char ** s = NULL, 464 00:35:52,380 --> 00:35:55,610 אתה יכול malloc מקום שלמחרוזת. 465 00:35:55,610 --> 00:36:04,230 אנחנו יכולים לעשות malloc (sizeof) - sizeof מה? 466 00:36:09,910 --> 00:36:15,190 [תלמיד] (char) * 5? >> האם זה נראה נכון? 467 00:36:15,190 --> 00:36:21,060 אני מניח שזה יעבוד אם אני ממש רציתי אותו, אבל זה לא מה שאני מחפש. 468 00:36:24,400 --> 00:36:32,940 תראה את הסוג של. בואו נוסיף * int, אז int * x. 469 00:36:32,940 --> 00:36:35,600 הייתי עושה malloc (sizeof (int)). 470 00:36:35,600 --> 00:36:40,490 או אם אני רוצה מערך של 5, שהייתי עושה (sizeof (int) * 5); 471 00:36:40,490 --> 00:36:44,210 מה אם יש לי ** int? 472 00:36:46,260 --> 00:36:49,140 מה הייתי malloc? 473 00:36:49,140 --> 00:36:53,510 [תלמיד] גודל של המצביע. >> כן. (Sizeof (int *)); 474 00:36:53,510 --> 00:36:56,960 אותו דבר כאן. 475 00:36:56,960 --> 00:37:01,280 אני רוצה (sizeof (char *)); 476 00:37:06,170 --> 00:37:12,840 זה הולך להקצות שטח למצביע שמצביע על "בום". 477 00:37:12,840 --> 00:37:15,330 אני לא צריך להקצות שטח ל" בום "עצמו 478 00:37:15,330 --> 00:37:17,210 כי זה בעצם שווה ערך למה שאמרתי קודם 479 00:37:17,210 --> 00:37:20,870 של char * x = "בום". 480 00:37:20,870 --> 00:37:27,950 "בום" כבר קיים. זה קורה לקיים באזור לקריאה בלבד של זיכרון. 481 00:37:27,950 --> 00:37:35,200 אבל זה כבר קיים, מה שאומר שהקו הזה של קוד, אם S הוא ** char, 482 00:37:35,200 --> 00:37:43,900 אז * זה * הוא char ואתה קובע * char זה כדי להצביע על "בום". 483 00:37:43,900 --> 00:37:50,040 אם אני רוצה להעתיק "בום" לים, אז לא הייתי צריך להקצות שטח לים. 484 00:37:55,170 --> 00:38:03,900 אני אעשה * s = malloc (sizeof (char) * 5); 485 00:38:03,900 --> 00:38:06,210 למה 5? 486 00:38:06,210 --> 00:38:10,860 למה לא 4? זה נראה כמו "בום" הוא 4 תווים. >> [תלמיד] דמות האפס. 487 00:38:10,860 --> 00:38:14,580 כן. כל המחרוזות שלך הולכים צריך תו null. 488 00:38:14,580 --> 00:38:23,590 עכשיו אני יכול לעשות משהו כמו strcat - מה תפקידו להעתקת מחרוזת? 489 00:38:23,590 --> 00:38:28,520 [תלמיד] פ י? >> Strcpy. 490 00:38:28,520 --> 00:38:32,700 strcpy אדם. 491 00:38:36,120 --> 00:38:39,590 אז strcpy או strncpy. 492 00:38:39,590 --> 00:38:43,410 strncpy הוא קצת יותר בטוח מאז שאתה יכול לציין בדיוק כמה תווים, 493 00:38:43,410 --> 00:38:46,190 אבל כאן זה לא משנה כי אנחנו יודעים. 494 00:38:46,190 --> 00:38:50,340 אז strcpy ולהסתכל בטענות. 495 00:38:50,340 --> 00:38:53,100 הטיעון הראשון הוא היעד שלנו. 496 00:38:53,100 --> 00:38:56,770 הטיעון השני הוא המקור שלנו. 497 00:38:56,770 --> 00:39:10,310 אנחנו הולכים להעתיק ל* היעד שלנו זה המצביע "בום". 498 00:39:10,310 --> 00:39:19,820 למה אולי אתה רוצה לעשות את זה עם strcpy במקום רק את מה שהיינו לפני 499 00:39:19,820 --> 00:39:22,800 * משל = "בום"? 500 00:39:22,800 --> 00:39:28,630 יש סיבה לכך אולי כדאי לך לעשות את זה, אבל מה היא הסיבה ש? 501 00:39:28,630 --> 00:39:31,940 [תלמיד] אם אתה רוצה לשנות משהו ב" בום ". >> כן. 502 00:39:31,940 --> 00:39:37,950 עכשיו אני יכול לעשות משהו כמו של [0] = "X"; 503 00:39:37,950 --> 00:39:48,190 משום שנקודתי s לערימה ושטח שעל הערימה שזה מצביעות על 504 00:39:48,190 --> 00:39:52,320 הוא מצביע למקום נוסף על הערמה, אשר האחסון "בום". 505 00:39:52,320 --> 00:39:55,150 אז עותק זה של "בום" הוא להיות מאוחסן בערימה. 506 00:39:55,150 --> 00:39:58,780 מבחינה טכנית יש שני עותקים של "בום" בתכנית שלנו. 507 00:39:58,780 --> 00:40:03,500 יש הראשון שרק ניתנים על ידי המתמיד הזה "בום" המחרוזת, 508 00:40:03,500 --> 00:40:09,250 והעותק השני של "בום", strcpy יצר עותק של "בום". 509 00:40:09,250 --> 00:40:13,100 אבל העותק של "בום" הוא להיות מאוחסן בערימה, והערימה אתה חופשי לשנות. 510 00:40:13,100 --> 00:40:17,250 הערימה היא לא לקריאה בלבד, כך שמשמעות היא שנ [0] 511 00:40:17,250 --> 00:40:20,500 הוא הולך לתת לך לשנות את הערך של "בום". 512 00:40:20,500 --> 00:40:23,130 זה הולך לתת לך לשנות את התווים האלה. 513 00:40:23,130 --> 00:40:26,640 >> שאלות? 514 00:40:27,740 --> 00:40:29,290 אוקיי. 515 00:40:29,290 --> 00:40:35,500 >> על מנת להזיז buggy3, gdb buggy3 בואו. 516 00:40:35,500 --> 00:40:39,840 אנחנו פשוט להפעיל אותו ואנחנו רואים שאנחנו מקבלים segfault. 517 00:40:39,840 --> 00:40:46,550 אם אנחנו backtrace, יש רק שתי פונקציות. 518 00:40:46,550 --> 00:40:52,970 אם אנחנו הולכים עד לפונקציה העיקרית שלנו, אנו רואים שsegfaulted בקו הזה. 519 00:40:52,970 --> 00:41:00,180 אז פשוט מסתכל על שורה זו, ל( int קו = 0; fgets החומר הזה עושה NULL לא שווה; 520 00:41:00,180 --> 00:41:03,770 שורה + +). 521 00:41:03,770 --> 00:41:08,010 המסגרת הקודמת שלנו נקראת _IO_fgets. 522 00:41:08,010 --> 00:41:10,720 אתה תראה את זה הרבה עם פונקציות C מובנהיות, 523 00:41:10,720 --> 00:41:15,350 כי כאשר אתה מקבל segfault, יהיו שמות פונקציות באמת מסתוריים 524 00:41:15,350 --> 00:41:18,090 כמו _IO_fgets זה. 525 00:41:18,090 --> 00:41:21,770 אבל זה הולך להתייחס לשיחת fgets זה. 526 00:41:21,770 --> 00:41:25,850 איפשהו בתוך כאן, אנו segfaulting. 527 00:41:25,850 --> 00:41:30,340 אם אנחנו מסתכלים על הטיעונים לfgets, אנחנו יכולים להדפיס חיץ. 528 00:41:30,340 --> 00:41:41,180 בואו להדפיס כ-- הו, לא. 529 00:41:48,980 --> 00:41:51,900 הדפסה היא לא הולכת לעבוד בדיוק כמו שאני רוצה אותו. 530 00:41:55,460 --> 00:41:58,000 בואו נסתכל על התכנית בפועל. 531 00:42:02,200 --> 00:42:09,640 חיץ הוא מערך תווים. זה מערך תווים של 128 תווים. 532 00:42:09,640 --> 00:42:14,980 לכן, כאשר אני אומר מאגר ההדפסה, זה הולך להדפיס 128 התווים האלה, 533 00:42:14,980 --> 00:42:18,300 אני מניח שזה מה שצפוי. 534 00:42:18,300 --> 00:42:21,390 מה שאני מחפש הוא להדפיס את הכתובת של מאגר, 535 00:42:21,390 --> 00:42:23,680 אבל זה לא באמת אומר לי הרבה. 536 00:42:23,680 --> 00:42:30,770 לכן, כאשר אני במקרה לומר עד כאן חיץ x, זה מראה לי 0xbffff090, 537 00:42:30,770 --> 00:42:38,690 אשר, אם אתה זוכר מקודם או איזו נקודה, Oxbffff נוטה להיות אזור מחסנית-ish. 538 00:42:38,690 --> 00:42:46,020 הערימה נוטה להתחיל איפשהו מתחת 0xc000. 539 00:42:46,020 --> 00:42:51,890 רק על ידי רואה הכתובת הזאת, אני יודע שחיץ שקורה בערימה. 540 00:42:51,890 --> 00:43:04,500 הפעלה מחדש של התכנית שלי, לרוץ, למעלה, חיץ שראינו היה זה רצף של תווים 541 00:43:04,500 --> 00:43:06,530 שהם פחות או יותר חסרי משמעות. 542 00:43:06,530 --> 00:43:12,270 אז הדפסת קובץ, מה קובץ נראה? 543 00:43:15,120 --> 00:43:17,310 [תלמיד] ריק. >> כן. 544 00:43:17,310 --> 00:43:22,610 קובץ הוא מסוג קובץ *, כך שזה הוא מצביע, 545 00:43:22,610 --> 00:43:26,610 והערך של מצביע הוא ריק. 546 00:43:26,610 --> 00:43:33,240 אז fgets הולך לנסות לקרוא שמהמצביע בדרך עקיפה, 547 00:43:33,240 --> 00:43:37,320 אבל כדי לגשת מצביע זה, זה צריך dereference. 548 00:43:37,320 --> 00:43:40,550 לחלופין, על מנת לגשת מה זה צריך להיות מכוון ל, זה dereferences זה. 549 00:43:40,550 --> 00:43:43,810 אז זה ביטול הפנית מצביע null וזה segfaults. 550 00:43:46,600 --> 00:43:48,730 הייתי יכול להפעיל מחדש את זה שם. 551 00:43:48,730 --> 00:43:52,170 אם נשבר בנקודה העיקרית שלנו ולרוץ, 552 00:43:52,170 --> 00:43:57,320 השורה הראשונה של קוד היא char * filename = "nonexistent.txt"; 553 00:43:57,320 --> 00:44:00,870 זה צריך לתת לי רמז די גדול, מדוע תכנית זו תיכשל. 554 00:44:00,870 --> 00:44:06,080 ההקלדה הבאה מביאה אותי לשורה הבאה, שבו אני פותח את הקובץ הזה, 555 00:44:06,080 --> 00:44:11,140 ואז אני מקבל מייד לקו שלנו, שבו ברגע שאפגע בפעם הבאה, זה הולך segfault. 556 00:44:11,140 --> 00:44:16,880 האם מישהו רוצה לזרוק את הסיבה שאנו יכולים להיות segfaulting? 557 00:44:16,880 --> 00:44:19,130 [תלמיד] קובץ לא קיים. >> כן. 558 00:44:19,130 --> 00:44:22,250 זה אמור להיות רמז 559 00:44:22,250 --> 00:44:29,570 כי בכל פעם שאתה פותח קובץ אתה צריך לבדוק שהקובץ באמת קיים. 560 00:44:29,570 --> 00:44:31,510 אז הנה, "nonexistent.txt"; 561 00:44:31,510 --> 00:44:34,700 כשקובץ fopen לקריאה, אז אנחנו צריכים לומר 562 00:44:34,700 --> 00:44:45,870 אם (הקובץ == NULL) ואומרים printf ("קובץ לא קיים!" 563 00:44:45,870 --> 00:44:56,340 או - יותר נכון - קובץ); תמורה 1; 564 00:44:56,340 --> 00:45:00,300 אז עכשיו אנחנו בודקים אם זה NULL 565 00:45:00,300 --> 00:45:03,930 לפני למעשה ממשיך ומנסה לקרוא מן הקובץ. 566 00:45:03,930 --> 00:45:08,800 אנחנו יכולים לשנות את זה רק כדי לראות שזה עובד. 567 00:45:11,020 --> 00:45:14,970 אני מתכוון לכלול בשורה חדשה. 568 00:45:21,090 --> 00:45:25,290 אז עכשיו nonexistent.txt לא קיים. 569 00:45:26,890 --> 00:45:30,040 אתה תמיד צריך לבדוק לדברים מהסוג הזה. 570 00:45:30,040 --> 00:45:33,870 אתה תמיד צריך לבדוק אם fopen מחזיר NULL. 571 00:45:33,870 --> 00:45:38,170 אתה תמיד צריך לבדוק כדי לוודא שmalloc לא מחזיר NULL, 572 00:45:38,170 --> 00:45:41,410 אחרת אתה segfault. 573 00:45:42,200 --> 00:45:45,930 >> עכשיו buggy4.c. 574 00:45:49,190 --> 00:45:58,440 פועל. אני מנחש שזה מחכה לקלט או לולאות אינסופיות, אולי. 575 00:45:58,440 --> 00:46:01,870 כן, זה לולאות אינסופיות. 576 00:46:01,870 --> 00:46:05,560 אז buggy4. זה נראה כאילו אנחנו לולאות אינסופיות. 577 00:46:05,560 --> 00:46:12,590 אנחנו יכולים לשבור בראשי, להפעיל את התכנית שלנו. 578 00:46:12,590 --> 00:46:20,180 בgdb, כל עוד אתה משתמש בקיצור הוא חד משמעי 579 00:46:20,180 --> 00:46:23,420 או קיצורים מיוחדים שהם מספקים עבורך, 580 00:46:23,420 --> 00:46:29,020 אז אתה יכול להשתמש n להשתמש הבא, במקום להקליד את כל הדרך הבאה. 581 00:46:29,020 --> 00:46:33,730 ועכשיו, אחרי שפגעתי n פעם אחת, אני יכול פשוט מקיש על Enter כדי להמשיך הבא 582 00:46:33,730 --> 00:46:36,640 במקום שיש להכות n זן, זן n, n Enter. 583 00:46:36,640 --> 00:46:44,630 זה נראה כאילו אני באיזה לולאה לזה הגדרת מערך [i] ל 0. 584 00:46:44,630 --> 00:46:50,510 זה נראה כאילו אני לא אפרוץ מזה ללולאה. 585 00:46:50,510 --> 00:46:54,780 אם אני מדפיס אני, אז הוא 2, אז אני אלך בא. 586 00:46:54,780 --> 00:46:59,250 אני אדפיס אני, אני הוא 3, אז אני אלך בא. 587 00:46:59,250 --> 00:47:05,360 אני אדפיס אני ואני הוא 3. בשלב בא, להדפיס, i היא 4. 588 00:47:05,360 --> 00:47:14,520 למעשה, ההדפסה sizeof (מערך), ולכן גודל של מערך הוא 20. 589 00:47:16,310 --> 00:47:32,870 אבל זה נראה כאילו יש איזה פקודת gdb מיוחדת להולך עד שמשהו קורה. 590 00:47:32,870 --> 00:47:37,620 זה כמו הגדרת תנאי על הערך של המשתנה. אבל אני לא זוכר מה זה. 591 00:47:37,620 --> 00:47:44,100 אז אם אנחנו ממשיכים הלאה - 592 00:47:44,100 --> 00:47:47,120 מה אמר? בשביל מה הבאת את? 593 00:47:47,120 --> 00:47:50,500 [תלמיד] האם להציג אני מוסיף - >> כן. אז להציג אני יכול לעזור. 594 00:47:50,500 --> 00:47:54,530 אם אנחנו רק להציג לי, זה יהיה לשים כאן מה הערך של i הוא 595 00:47:54,530 --> 00:47:56,470 אז אני לא צריך להדפיס אותו בכל פעם. 596 00:47:56,470 --> 00:48:02,930 אם אנחנו פשוט להמשיך הבאים, אנו רואים 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5. 597 00:48:02,930 --> 00:48:08,530 משהו מאוד לא בסדר קורה, ואני נמצא באיפוס ל 0. 598 00:48:13,330 --> 00:48:22,220 כאשר מסתכלים על buggy4.c, אנו רואים כל מה שקורה הוא מערך int [5]; 599 00:48:22,220 --> 00:48:26,200 עבור (i = 0; i <= sizeof (מערך); אני + +) 600 00:48:26,200 --> 00:48:28,550 מערך [i] = 0; 601 00:48:28,550 --> 00:48:31,390 מה שאנחנו כן רואים שלא בסדר כאן? 602 00:48:31,390 --> 00:48:39,480 כרמז, כשאני עושה gdb buggy4 - בואו לשבור ראשי, טווח - 603 00:48:39,480 --> 00:48:45,980 אני לא ההדפסה sizeof (מערך) רק כדי לראות מה המצב שבו אני צריך סוף סוף אפרוץ. 604 00:48:47,690 --> 00:48:51,100 איפה אני? האם אני רץ? 605 00:48:51,100 --> 00:48:54,280 אני לא הכרזתי עדיין. 606 00:48:54,280 --> 00:48:58,680 אז להדפיס sizeof (מערך) וזה 20, 607 00:48:58,680 --> 00:49:06,690 אשר צפוי מאז המערך שלי הוא בגודל 5 וזה של 5 מספרים שלמים, 608 00:49:06,690 --> 00:49:12,410 לכן כל הדבר צריך להיות 5 * בתי sizeof (int), שבו sizeof (int) נוטה להיות 4. 609 00:49:12,410 --> 00:49:14,780 אז sizeof (מערך) הוא 20. 610 00:49:14,780 --> 00:49:17,420 מה זה צריך להיות? 611 00:49:17,420 --> 00:49:21,720 [תלמיד] לחלק ב sizeof (int). >> כן, / sizeof (int). 612 00:49:21,720 --> 00:49:30,630 זה נראה כאילו יש עדיין בעיה כאן. אני חושב שזה צריך פשוט להיות < 613 00:49:30,630 --> 00:49:36,960 מכיוון שזה פחות או יותר תמיד <ולא <=. 614 00:49:36,960 --> 00:49:44,860 עכשיו בואו נחשוב למה זה היה שבור ממש. 615 00:49:44,860 --> 00:49:53,370 למישהו יש ניחושים למה הייתי לאפס ל 0 דרך כל איטרציה של הלולאה? 616 00:50:01,300 --> 00:50:09,350 הדבר היחיד שנותר מכאן שקורה הוא שהמערך [i] היא להיות מוגדרת 0. 617 00:50:09,350 --> 00:50:15,350 אז איכשהו, הקו הזה של קוד גורם int שלנו אני להיות מוגדר 0. 618 00:50:16,730 --> 00:50:23,130 [תלמיד] האם זה יכול להיות בגלל שזה מבטל את הזיכרון של חלק זה שלי 619 00:50:23,130 --> 00:50:27,970 כאשר הוא חושב שזה האלמנט הבא של מערך? >> [אודן] כן. 620 00:50:27,970 --> 00:50:33,880 כאשר אנחנו הולכים מעבר לסוף המערך שלנו, 621 00:50:33,880 --> 00:50:39,870 איכשהו מרחב שבו אנו דריסתו דריסת הערך של i. 622 00:50:39,870 --> 00:50:48,030 ולכן אם אנחנו מסתכלים לתוך buggy4, לשבור, ריצה עיקרית, 623 00:50:48,030 --> 00:50:53,120 בואו להדפיס את הכתובת של i. 624 00:50:53,120 --> 00:50:57,280 זה נראה כמו שזה bffff124. 625 00:50:57,280 --> 00:51:03,930 עכשיו בואו להדפיס את הכתובת של מערך [0]. 110. 626 00:51:03,930 --> 00:51:06,290 מה לגבי [1]? 114. 627 00:51:06,290 --> 00:51:07,920 [2], 118. 628 00:51:07,920 --> 00:51:14,530 11c, 120. מערך [5] הוא bfff124. 629 00:51:14,530 --> 00:51:26,990 אז מערך [5] יש אותה הכתובת כמו שאני, מה שאומר שהמערך [5] הוא אני. 630 00:51:26,990 --> 00:51:30,720 אם יש להם את אותה כתובת, שהם אותו הדבר. 631 00:51:30,720 --> 00:51:38,410 לכן, כאשר אנו קובעים מערך [5] ל 0, אנו קובעים שכדי 0. 632 00:51:38,410 --> 00:51:46,070 אם אתה חושב על זה במונחים של המחסנית ו, 633 00:51:46,070 --> 00:51:55,590 אני int מוצהר ראשון, מה שאומר שאני מקבל קצת מקום במחסנית. 634 00:51:55,590 --> 00:52:04,730 אז מערך [5] מוקצה, אז 20 בתים מוקצים על המחסנית. 635 00:52:04,730 --> 00:52:08,400 אז אני מקבל מוקצה תחילה, ולאחר מכן 20 בתים אלה לקבל שהוקצו. 636 00:52:08,400 --> 00:52:11,400 אז אני קורה ממש לפני המערך, 637 00:52:11,400 --> 00:52:19,230 ובגלל הדרך, כמו שאמרתי בשבוע שעבר, שבו מבחינה טכנית המחסנית גדלה כלפי מטה, 638 00:52:19,230 --> 00:52:28,520 כאשר אינדקס לתוך מערך, מובטחים לנו כי העמדה 0 במערך 639 00:52:28,520 --> 00:52:31,970 תמיד קורה לפני המיקום הראשון במערך. 640 00:52:31,970 --> 00:52:35,900 זה סוג של איך שלפתי אותה בשבוע שעבר. 641 00:52:35,900 --> 00:52:42,210 שים לב כי בחלק התחתון יש לנו כתובה 0 ובראש יש לנו מקס כתובת. 642 00:52:42,210 --> 00:52:44,880 הערימה מתרחבת תמיד כלפי מטה. 643 00:52:48,100 --> 00:52:53,500 נניח שאנו מקצים לי. 644 00:52:53,500 --> 00:52:59,680 אנו מקצים מספר שלמים אני, מה שאומר בואו נגיד עד כאן אני מקבל מספר שלם שהוקצה. 645 00:52:59,680 --> 00:53:06,420 ואז אנו מקצים המערך שלנו של 5 מספרים שלמים, מה שאומר שמתחת לזה, 646 00:53:06,420 --> 00:53:11,230 מאז שהערימה גדלה למטה, 5 המספרים שלמים האלה, מי שהוקצה. 647 00:53:11,230 --> 00:53:15,900 אבל בגלל כמה מערכים יעבדו, אנחנו מובטחים שהמיקום הראשון במערך 648 00:53:15,900 --> 00:53:22,260 תמיד יש כתובת פחות מהדבר השני במערך. 649 00:53:22,260 --> 00:53:28,270 אז 0 עמדת המערך תמיד צריך לקרות ראשון בזיכרון, 650 00:53:28,270 --> 00:53:30,700 ואילו עמדת מערך 1 צריכה לקרות אחרי ש 651 00:53:30,700 --> 00:53:33,310 ועמדת מערך 2 צריכה לקרות אחרי זה, 652 00:53:33,310 --> 00:53:37,900 מה שאומר ש0 עמדת המערך יקרו איפשהו כאן למטה, 653 00:53:37,900 --> 00:53:40,690 עמדת מערך 1 תקרה לעיל כי 654 00:53:40,690 --> 00:53:45,530 משום שנע מעלה פירוש כתובות גבוהות מאז הכתובת המרבית היא עד כאן. 655 00:53:45,530 --> 00:53:50,490 אז מערך [0] כאן למטה, מערך [1] עד כאן, מערך [2] עד כאן, מערך [3] עד כאן. 656 00:53:50,490 --> 00:53:55,620 שים לב איך לפני שהוקצינו שלם אני כל הדרך עד לכאן, 657 00:53:55,620 --> 00:54:01,040 בעודנו נעים יותר ויותר לתוך המערך שלנו, אנו מתקרבים יותר ויותר למספר השלם אני. 658 00:54:01,040 --> 00:54:07,640 זה פשוט כל כך קורה כי המערך [5], שהוא מעבר לעמדה אחת המערך שלנו, 659 00:54:07,640 --> 00:54:13,010 הוא בדיוק איפה שלם יצאתי לי להיות מוקצה. 660 00:54:13,010 --> 00:54:16,920 אז זה הנקודה שבה אנחנו במקרה להכות את החלל במחסנית 661 00:54:16,920 --> 00:54:21,680 שהוקצה למספר השלם i, ואנחנו קביעה כי ל 0. 662 00:54:21,680 --> 00:54:26,160 >> ככה זה עובד. שאלות? כן. 663 00:54:26,160 --> 00:54:30,710 [תלמיד] לא משנה. אוקיי. 664 00:54:30,710 --> 00:54:33,090 [תלמיד] איך נמנע מאלה מעין שגיאות? 665 00:54:33,090 --> 00:54:41,190 אלה מעין שגיאות? אל תשתמש בשפת תכנות C כ. 666 00:54:41,190 --> 00:54:45,840 השתמש בשפה זו יש גבולות מערך בדיקה. 667 00:54:45,840 --> 00:54:55,900 כל עוד אתה זהיר, אתה פשוט צריך להימנע מהעבר מגבולות המערך שלך. 668 00:54:55,900 --> 00:54:58,300 [תלמיד] אז הנה כשעברנו את גבולות מערכך - 669 00:54:58,300 --> 00:55:01,840 [אודן] זה שבו דברים מתחילים להשתבש. >> [תלמיד] אה, בסדר. 670 00:55:01,840 --> 00:55:05,730 כל עוד אתה נשאר בתוך הזיכרון שהוקצה למערך שלך, אתה בסדר. 671 00:55:05,730 --> 00:55:12,400 אבל ג'לא עושה בדיקת שגיאות. אם אני עושה את המערך [1000], זה יהיה בשמחה פשוט לשנות כל מה שקורה - 672 00:55:12,400 --> 00:55:16,500 זה הולך לתחילת המערך, אז זה הולך אחרי 1000 עמדות ומניח אותו על 0. 673 00:55:16,500 --> 00:55:20,000 זה לא עושה כל בדיקה שהו, זה לא באמת יש 1000 דברים בזה. 674 00:55:20,000 --> 00:55:22,750 1000 הם הרבה מעבר למה שאני צריך שינוי, 675 00:55:22,750 --> 00:55:26,940 בעוד ג'אווה או משהו שתקבלי מערך מאינדקס של גבולות 676 00:55:26,940 --> 00:55:29,820 או מדד מתוך גבולות חריג. 677 00:55:29,820 --> 00:55:33,950 זו הסיבה שהרבה שפות ברמה גבוהות יותר יש את הדברים האלה 678 00:55:33,950 --> 00:55:37,340 שם אם אתה רוצה ללכת מעבר לגבולות של המערך, אתה נכשל 679 00:55:37,340 --> 00:55:40,070 כך שאתה לא יכול לשנות את הדברים מתחתיך 680 00:55:40,070 --> 00:55:42,590 ואז דברים ילכו הרבה יותר גרועים מסתם מקבל חריג 681 00:55:42,590 --> 00:55:44,940 אמר שהלכת מעבר לסוף המערך. 682 00:55:44,940 --> 00:55:50,970 [תלמיד] וכך צריך יש לנו רק שיניתי את <= רק > [אודן] כן. 683 00:55:50,970 --> 00:55:54,800 זה צריך להיות 00:55:59,560 מאז sizeof (מערך) הוא 20, אבל אנחנו רוצים רק 5. >> [תלמיד] ימני. 685 00:55:59,560 --> 00:56:04,060 עוד שאלות? אוקיי. 686 00:56:04,060 --> 00:56:07,380 >> [תלמיד] יש לי שאלה. >> כן. 687 00:56:07,380 --> 00:56:16,440 [תלמיד] מהו משתנה המערך בפועל? 688 00:56:16,440 --> 00:56:20,000 [אודן] כמו מה הוא מערך? 689 00:56:20,000 --> 00:56:24,930 המערך עצמו הוא סמל. 690 00:56:24,930 --> 00:56:31,490 זה רק את הכתובת של תחילת שנתי ה 20 הבתים שאנו מפנים. 691 00:56:31,490 --> 00:56:38,070 אתה יכול לחשוב על זה כמצביע, אך הוא מצביע קבוע. 692 00:56:38,070 --> 00:56:44,140 ברגע שהדברים מקבלים הידור, המערך משתנה כבר לא קיים. 693 00:56:44,140 --> 00:56:48,210 [תלמיד] אז איך זה למצוא את גודלו של מערך? 694 00:56:48,210 --> 00:56:54,130 גודלו של מערך מתייחס לגודל של שהבלוק שהסמל שמתייחס ל. 695 00:56:54,130 --> 00:57:01,240 כשאני עושה משהו כמו printf ("% p \ n", מערך); 696 00:57:01,240 --> 00:57:05,140 בואו להפעיל אותו. 697 00:57:12,960 --> 00:57:15,530 מה הדבר האחרון שעשיתי בסדר? 698 00:57:15,530 --> 00:57:19,220 'המערך' המערך הכריז כאן. 699 00:57:20,820 --> 00:57:23,200 אה, עד כאן. 700 00:57:23,200 --> 00:57:31,250 הצלצול הוא חכם, וזה קורה ללב שאני הכרזתי מערך כ5 אלמנטים 701 00:57:31,250 --> 00:57:34,540 אבל אני אינדוקס למקום 1000. 702 00:57:34,540 --> 00:57:38,450 זה יכול לעשות את זה כי אלה הם רק בקבועים. 703 00:57:38,450 --> 00:57:43,370 זה יכול להגיע רק עד נקודה בלב שאני עומד מעבר לגבולות של המערך. 704 00:57:43,370 --> 00:57:46,880 אבל שם לב שהיינו לנו קודם לכן, כאשר אני להיות שגוי, 705 00:57:46,880 --> 00:57:51,040 אין זה אפשרי לקבוע כמה ערכים שאני יכול לקחת על, 706 00:57:51,040 --> 00:57:55,540 כך שזה לא יכול לקבוע שאני הולך אל מעבר לסוף המערך. 707 00:57:55,540 --> 00:57:59,430 זה פשוט קלאנג להיות חכם. 708 00:57:59,430 --> 00:58:03,340 >> אבל עכשיו לעשות buggy4. אז מה עוד אני עושה לא בסדר? 709 00:58:03,340 --> 00:58:05,970 במרומז הכרזת פונקצית ספרייה 'printf'. 710 00:58:05,970 --> 00:58:14,960 אני הולך לרוצה # לכלול . 711 00:58:14,960 --> 00:58:18,710 אוקיי. כעת פועל buggy4. 712 00:58:18,710 --> 00:58:24,840 להדפיס את הערך של המערך כמו שעשיתי כאן, להדפיס אותו כמצביע 713 00:58:24,840 --> 00:58:30,060 משהו הדפסים שנראה כך - bfb8805c - שהוא חלק הכתובת 714 00:58:30,060 --> 00:58:33,450 זה באזור מחסנית-ish. 715 00:58:33,450 --> 00:58:41,820 מערך עצמו הוא כמו מצביע, אבל זה לא מצביע בפועל, 716 00:58:41,820 --> 00:58:45,410 מאז מצביע רגיל אנחנו יכולים לשנות. 717 00:58:45,410 --> 00:58:54,700 מערך הוא רק חלק קבוע. 20 בלוקים של זיכרון מתחילים ב 0xbfb8805c כתובת. 718 00:58:54,700 --> 00:59:09,020 אז bfb8805c דרך כתובת זו +20- או אני מניח -20 - 719 00:59:09,020 --> 00:59:17,400 הוא כל הזיכרון שהוקצה למערך זה. 720 00:59:17,400 --> 00:59:20,350 מערך, משתנה עצמו אינו מאוחסן בכל מקום. 721 00:59:20,350 --> 00:59:27,660 כשאתה קומפילציה, מהדר - גל יד בזה - 722 00:59:27,660 --> 00:59:33,060 אבל מהדר פשוט להשתמש בה יודע מערך להיות. 723 00:59:33,060 --> 00:59:36,090 הוא יודע איפה מערך שמתחיל, 724 00:59:36,090 --> 00:59:40,910 ולכן הוא יכול תמיד פשוט לעשות את דברים במונחים של קיזוז שמההתחלה. 725 00:59:40,910 --> 00:59:43,960 היא לא צריכה לייצג את עצמו משתנה מערך. 726 00:59:43,960 --> 00:59:53,730 אבל כשאני עושה משהו כזה int * p = מערך, עכשיו p הוא מצביע שמצביע שמערך, 727 00:59:53,730 --> 00:59:57,830 ועכשיו p אכן מקיים במחסנית. 728 00:59:57,830 --> 01:00:01,950 אני חופשי לשנות p. אני יכול לעשות p = malloc. 729 01:00:01,950 --> 01:00:06,500 אז זה המקור הצביע למערך, עכשיו הוא מצביע למקום כלשהו בערימה. 730 01:00:06,500 --> 01:00:09,620 אני לא יכול לעשות malloc = מערך. 731 01:00:09,620 --> 01:00:13,710 אם קלאנג הוא חכם, הוא צועק עליי מייד את הבת. 732 01:00:17,000 --> 01:00:21,430 למעשה, אני די בטוח שgcc הייתי עושה גם. 733 01:00:21,430 --> 01:00:25,010 אז סוג המערך 'int [5]' אינו ניתן להעברה. 734 01:00:25,010 --> 01:00:28,040 לא ניתן להקצות משהו לסוג מערך 735 01:00:28,040 --> 01:00:30,500 כי המערך הוא פשוט קבוע. 736 01:00:30,500 --> 01:00:34,760 זהו סמל שההפניות 20 הבתים הללו. אני לא יכול לשנות את זה. 737 01:00:34,760 --> 01:00:37,690 >> [תלמיד] ואיפה הגודל של המערך מאוחסן? 738 01:00:37,690 --> 01:00:40,670 [אודן] זה לא מאוחסן בכל מקום. זה כאשר זה הידור. 739 01:00:40,670 --> 01:00:46,310 אז איפה הוא בגודל של מערך מאוחסן? 740 01:00:46,310 --> 01:00:51,870 אתה יכול להשתמש בsizeof (מערך) רק בתוך הפונקציה שהמערך הכריז על עוצמה. 741 01:00:51,870 --> 01:01:03,150 אז אם אני עושה את תפקיד כלשהו, ​​foo, ואני עושה (int מערך []) 742 01:01:03,150 --> 01:01:10,450 printf ("% d \ n", sizeof (מערך)); 743 01:01:10,450 --> 01:01:21,330 ואז אני קורא כאן foo (מערך); 744 01:01:21,330 --> 01:01:24,840 בתוך פונקציה זו - בואו להפעיל אותו. 745 01:01:34,200 --> 01:01:36,840 זה קלאנג להיות חכם שוב. 746 01:01:36,840 --> 01:01:43,890 הוא אומר לי שעל פרמטר sizeof פונקצית מערך 747 01:01:43,890 --> 01:01:46,690 יחזור גודלו של "* int". 748 01:01:46,690 --> 01:01:55,150 זו תהיה שגיאה אם ​​זה לא מה שרציתי שקורה. 749 01:01:55,150 --> 01:01:58,960 בואו בעצם לכבות Werror. 750 01:02:14,950 --> 01:02:17,590 אזהרה. אזהרות הן בסדר גמורות. 751 01:02:17,590 --> 01:02:19,960 זה עדיין יהיה לקמפל את זמן שיש לו אזהרה. 752 01:02:19,960 --> 01:02:22,910 a.out. / הולך להדפיס 4. 753 01:02:22,910 --> 01:02:28,650 האזהרה שנוצרה היא אינדיקציה ברורה של מה השתבש. 754 01:02:28,650 --> 01:02:34,120 מערך int זה רק הולך להדפיס sizeof (int *). 755 01:02:34,120 --> 01:02:39,790 גם אם אני מניח את המערך [5] בכאן, זה עדיין רק הולך להדפיס sizeof (int *). 756 01:02:39,790 --> 01:02:47,440 אז ברגע שאתה עובר אותו לפונקציה, ההבחנה בין מערכים ומצביעים 757 01:02:47,440 --> 01:02:49,670 הוא אפסי. 758 01:02:49,670 --> 01:02:52,640 זה קורה להיות מערך שהוכרז על הערימה, 759 01:02:52,640 --> 01:02:58,300 אבל ברגע שאנחנו מעבירים את הערך ש, ש0xbf בלה, בלה, בלה לפונקציה זו, 760 01:02:58,300 --> 01:03:03,350 אז מצביע זה מצביע שמערך על המחסנית. 761 01:03:03,350 --> 01:03:08,310 אז זה אומר שsizeof חל רק בפונקציה שהמערך הוכרז, 762 01:03:08,310 --> 01:03:11,230 מה שאומר שכאשר אתה קומפילצית פונקציה זו, 763 01:03:11,230 --> 01:03:17,330 כאשר קלאנג עובר בפונקציה זו, שהיא רואה מערך הוא מערך int בגודל 5. 764 01:03:17,330 --> 01:03:20,640 אז הוא רואה sizeof (מערך). טוב, זה 20. 765 01:03:20,640 --> 01:03:26,440 זה בעצם איך sizeof בעצם עובד כמעט בכל המקרים. 766 01:03:26,440 --> 01:03:31,150 Sizeof הוא לא פונקציה, זה מפעיל. 767 01:03:31,150 --> 01:03:33,570 אתה לא קורא את פונקצית sizeof. 768 01:03:33,570 --> 01:03:38,280 Sizeof (int), המהדר פשוט יתרגם את זה עד 4. 769 01:03:41,480 --> 01:03:43,700 יש את זה? אוקיי. 770 01:03:43,700 --> 01:03:47,520 >> [תלמיד] אז מהו ההבדל בין sizeof (מערך) ובעיקרי בfoo? 771 01:03:47,520 --> 01:03:52,840 הסיבה לכך היא שאנחנו אומרים sizeof (מערך), שהוא מסוג int *, 772 01:03:52,840 --> 01:03:57,120 ואילו המערך כאן למטה הוא לא מסוג int *, זה מערך int. 773 01:03:57,120 --> 01:04:04,540 >> [תלמיד] לכן אם היה הפרמטר במערך [] במקום מערך * int, 774 01:04:04,540 --> 01:04:09,230 זה היה אומר שאתה עדיין יכול לשנות את המערך כי עכשיו זה מצביע? 775 01:04:09,230 --> 01:04:14,250 [אודן] כמו זה? >> [תלמיד] כן. אתה יכול לשנות את המערך בתוך הפונקציה עכשיו? 776 01:04:14,250 --> 01:04:18,420 [אודן] אתה יכול לשנות את המערך בשני המקרים. 777 01:04:18,420 --> 01:04:23,130 בשני המקרים האלה אתה חופשי לומר מערך [4] = 0. 778 01:04:23,130 --> 01:04:26,590 [תלמיד] אבל אתה יכול להפוך את הנקודה של מערך למשהו אחר? 779 01:04:26,590 --> 01:04:30,230 [אודן] הו. כן. בכל מקרה - >> [תלמיד] כן. 780 01:04:30,230 --> 01:04:38,410 [אודן] ההבחנה בין מערך [] ומערך * int, אין כזה. 781 01:04:38,410 --> 01:04:42,570 גם אתה יכול לקבל כמה מערך רב ממדי בפה 782 01:04:42,570 --> 01:04:47,050 עבור חלק התחביר נוח, אבל זה עדיין רק מצביע. 783 01:04:47,050 --> 01:04:56,400 זה אומר שאני חופשי לעשות מערך = malloc (sizeof (int)); ועכשיו להצביע במקום אחר. 784 01:04:56,400 --> 01:04:59,610 אבל בדיוק כמו איך זה עובד לנצח, ותמיד, 785 01:04:59,610 --> 01:05:03,210 שינוי מערך זה בכך שהוא מצביע על משהו אחר 786 01:05:03,210 --> 01:05:07,570 אינו משנה את המערך הזה לכאן, כי זה עותק של הוויכוח, 787 01:05:07,570 --> 01:05:10,780 זה לא מצביע שלטענה. 788 01:05:10,780 --> 01:05:16,070 ובעצם, זה רק כאינדיקציה נוספת שזה בדיוק אותו הדבר - 789 01:05:16,070 --> 01:05:21,100 אנחנו כבר ראינו מה הדפסי מערך הדפסה - 790 01:05:21,100 --> 01:05:31,410 מה אם אנחנו מדפיסים את הכתובת של המערך או את הכתובת של הכתובת של המערך 791 01:05:31,410 --> 01:05:36,290 לאף אחד מאלה? 792 01:05:41,770 --> 01:05:45,220 בואו נתעלם מזה. 793 01:05:48,140 --> 01:05:51,660 אוקיי. זה בסדר גמור. עכשיו זה פועל. / A.out. 794 01:05:51,660 --> 01:06:00,220 מערך הדפסה, ולאחר מכן להדפיס את הכתובת של המערך, הוא אותו הדבר. 795 01:06:00,220 --> 01:06:02,870 מערך פשוט לא קיים. 796 01:06:02,870 --> 01:06:08,190 הוא יודע כשאתה מדפיס מערך, אתה מדפיס את הסמל המתייחס ל20 הבתים הללו. 797 01:06:08,190 --> 01:06:11,940 הדפסת הכתובת של המערך, טוב, מערך לא קיים. 798 01:06:11,940 --> 01:06:17,200 זה לא חייב כתובת, אז זה פשוט מדפיס את הכתובת של 20 הבתים הללו. 799 01:06:20,820 --> 01:06:28,150 ברגע שאתה לאסוף למטה, כמו בbuggy4 ההידור שלך. / A.out, 800 01:06:28,150 --> 01:06:30,340 מערך הוא אפסי. 801 01:06:30,340 --> 01:06:33,640 מצביעים קיימים. מערכים לא. 802 01:06:34,300 --> 01:06:38,060 אובניים זיכרון המייצג את המערך עדיין קיים, 803 01:06:38,060 --> 01:06:43,270 אבל המערך ומשתנה מהסוג משתנה לא קיימים. 804 01:06:46,260 --> 01:06:50,270 אלה הם כמו ההבדלים העיקריים בין מערכים ומצביעים 805 01:06:50,270 --> 01:06:55,590 הם ברגע שאתה לבצע שיחות פונקציה, אין הבדל. 806 01:06:55,590 --> 01:07:00,460 אבל בתוך הפונקציה שהמערך עצמו הצהיר, sizeof עובד אחרת 807 01:07:00,460 --> 01:07:05,190 מאז שאתה מדפיס את גודל הקוביות במקום בגודל של הסוג, 808 01:07:05,190 --> 01:07:08,950 ואתה לא יכול לשנות את זה כי זה סמל. 809 01:07:08,950 --> 01:07:14,370 הדפסת הדבר ואת כתובתו של הדבר מדפיסה את אותו הדבר. 810 01:07:14,370 --> 01:07:18,480 וזה פחות או יותר אותו. 811 01:07:18,480 --> 01:07:20,820 [תלמיד] האם אתה יכול לומר שעוד פעם אחת? 812 01:07:21,170 --> 01:07:24,170 שאולי פספסתי משהו. 813 01:07:24,170 --> 01:07:29,260 מערך הדפסה וכתובת של מערך מדפיסים את אותו דבר, 814 01:07:29,260 --> 01:07:33,180 ואילו, אם תדפיס מצביע לעומת הכתובת של המצביע, 815 01:07:33,180 --> 01:07:36,010 דבר אחד ידפיס את הכתובת של מה שאתה מצביע, 816 01:07:36,010 --> 01:07:40,360 האחרים מדפיס את הכתובת של המצביע על הערימה. 817 01:07:40,360 --> 01:07:47,040 באפשרותך לשנות מצביע, אתה לא יכול לשנות את סמל מערך. 818 01:07:47,740 --> 01:07:53,270 ומצביע sizeof הולך להדפיס בגודל של סוג המצביע. 819 01:07:53,270 --> 01:07:57,470 אז * p sizeof (p) הולך להדפיס int 4, 820 01:07:57,470 --> 01:08:04,110 אבל המערך [5] ההדפסה sizeof (מערך) הולך להדפיס int 20. 821 01:08:04,110 --> 01:08:07,480 [תלמיד] אז int מערך [5] ידפיס 20? >> כן. 822 01:08:07,480 --> 01:08:13,300 זו הסיבה הפנימית של buggy4 כשזה היה אמור להיות (מערך) sizeof 823 01:08:13,300 --> 01:08:16,660 זה עושה לי <20, וזה לא מה שרצינו. 824 01:08:16,660 --> 01:08:20,880 אנחנו רוצים i <5. >> [תלמיד] אוקיי. 825 01:08:20,880 --> 01:08:25,569 [אודן] ואז ברגע שאתה מתחיל לעבור בפונקציות, 826 01:08:25,569 --> 01:08:34,340 אם אנחנו לא int * p = מערך; 827 01:08:34,340 --> 01:08:39,779 בתוך פונקציה זו, אנו יכולים להשתמש בעיקרון עמ ומערך בדיוק באותן הדרכים, 828 01:08:39,779 --> 01:08:43,710 פרט לבעית sizeof ובעיה בשינוי. 829 01:08:43,710 --> 01:08:49,810 אבל p [0] = 1; הוא זהים אומר מערך [0] = 1; 830 01:08:49,810 --> 01:08:55,600 וברגע שאנחנו אומרים foo (מערך); או foo (p); 831 01:08:55,600 --> 01:08:59,760 בתוך פונקצית foo, זו אותה השיחה פעמים. 832 01:08:59,760 --> 01:09:03,350 אין הבדל בין שתי השיחות הללו. 833 01:09:07,029 --> 01:09:11,080 >> כולם טובים בזה? אוקיי. 834 01:09:14,620 --> 01:09:17,950 יש לנו 10 דקות. 835 01:09:17,950 --> 01:09:28,319 >> אנחנו ננסה להשיג באמצעות תכנית Typer ההאקר הזה, 836 01:09:28,319 --> 01:09:32,350 אתר זה, שיצא בשנה שעברה או משהו כזה. 837 01:09:34,149 --> 01:09:41,100 אבל זה אמור להיות כמו שאתה מקליד באופן אקראי וזה מדפיס את - 838 01:09:41,100 --> 01:09:46,729 לא משנה מה קובץ זה קורה לטען הוא מה זה נראה כמו שאתה מקליד. 839 01:09:46,729 --> 01:09:52,069 זה נראה כמו איזה קוד של מערכת הפעלה. 840 01:09:53,760 --> 01:09:56,890 זה מה שאנחנו רוצים ליישם. 841 01:10:08,560 --> 01:10:11,690 אתה צריך להיות בהפעלת ינארי השם hacker_typer 842 01:10:11,690 --> 01:10:14,350 שלוקח בויכוח אחד, את הקובץ "סוג ההאקר". 843 01:10:14,350 --> 01:10:16,480 ריצת ההפעלה צריכה לנקות את המסך 844 01:10:16,480 --> 01:10:20,850 ולאחר מכן להדפיס את תו אחד מהקובץ מחוסר הכרה בכל פעם שמשתמש לוחץ על מקש. 845 01:10:20,850 --> 01:10:24,990 אז לא משנה איזה מקש אתה לוחץ, זה צריך לזרוק ובמקום להדפיס דמות מהקובץ 846 01:10:24,990 --> 01:10:27,810 זה הוויכוח. 847 01:10:29,880 --> 01:10:34,350 אני די הרבה אגיד לך מה הדברים שאנחנו הולכים צריכים לדעת הם. 848 01:10:34,350 --> 01:10:36,440 אבל אנחנו רוצים לבדוק את ספריית termios. 849 01:10:36,440 --> 01:10:44,840 אני מעולם לא השתמשתי בספרייה זו בכל החיים שלי, אז יש לו מטרות מאוד מינימאליות. 850 01:10:44,840 --> 01:10:48,610 אבל זה הולך להיות הספרייה שאנחנו יכולים להשתמש בו כדי להשליך על האופי אתה מכה 851 01:10:48,610 --> 01:10:52,390 כאשר אתה מקליד לתוך סטנדרטי פנימה 852 01:10:56,970 --> 01:11:05,840 אז hacker_typer.c, ואנחנו הולכים לרוצים # לכלול . 853 01:11:05,840 --> 01:11:12,870 כאשר מסתכלים על דף האדם לtermios - אני מנחש מסוף מערכת הפעלה או שזה משהו - 854 01:11:12,870 --> 01:11:16,240 אני לא יודע איך לקרוא אותו. 855 01:11:16,240 --> 01:11:21,040 כאשר מסתכלים על זה, זה אומר לכלול 2 הקבצים האלה, ולכן אנחנו נעשה את זה. 856 01:11:37,620 --> 01:11:46,820 >> דבר הראשון ראשון, אנחנו רוצים לקחת בטענה אחת, שהוא הקובץ שאנחנו צריכים לפתוח. 857 01:11:46,820 --> 01:11:52,420 אז מה אני רוצה לעשות? כיצד ניתן לבדוק כדי לראות שיש לי טענה אחת? 858 01:11:52,420 --> 01:11:56,480 [תלמיד] אם argc שווה את זה. >> [אודן] כן. 859 01:11:56,480 --> 01:12:21,250 אז אם (argc = 2!) Printf ("שימוש:% s [קובץ כדי לפתוח]"). 860 01:12:21,250 --> 01:12:32,750 אז עכשיו אם אני מפעיל את זה מבלי לספק נימוק שני - אוי, אני צריך את הקו החדש - 861 01:12:32,750 --> 01:12:36,240 אתה רואה את זה אומר שימוש:. / hacker_typer, 862 01:12:36,240 --> 01:12:39,770 ולאחר מכן את הטענה השנייה צריכה להיות קובץ שאני רוצה לפתוח. 863 01:12:58,430 --> 01:13:01,260 עכשיו מה עליי לעשות? 864 01:13:01,260 --> 01:13:08,490 אני רוצה לקרוא מקובץ זה. כיצד ניתן לקרוא מקובץ? 865 01:13:08,490 --> 01:13:11,920 [תלמיד] אתה פותח אותו לראשונה. >> כן. 866 01:13:11,920 --> 01:13:15,010 אז fopen. מה fopen נראה? 867 01:13:15,010 --> 01:13:22,980 [תלמיד] שם קובץ. >> [אודן] שם הקובץ הולך להיות argv [1]. 868 01:13:22,980 --> 01:13:26,110 [תלמיד] ואז מה שאתה רוצה לעשות איתו, ולכן - >> [אודן] כן. 869 01:13:26,110 --> 01:13:28,740 אז אם אתה לא זוכר, אתה יכול פשוט לעשות fopen אדם, 870 01:13:28,740 --> 01:13:32,960 איפה זה הולך להיות דרך * char const path הוא שם קובץ, 871 01:13:32,960 --> 01:13:34,970 מצב * char const. 872 01:13:34,970 --> 01:13:38,660 אם קורה לך לא זוכר מה מצבו, ואז אתה יכול להסתכל על מצב. 873 01:13:38,660 --> 01:13:44,660 בתוך דפי אדם, תו הקו הוא מה שאתה יכול להשתמש בו כדי לחפש דברים. 874 01:13:44,660 --> 01:13:49,790 אז אני מקליד / מצב כדי לחפש מצב. 875 01:13:49,790 --> 01:13:57,130 n ו-N הם מה שאתה יכול להשתמש בו כדי לעבור בין תוצאות החיפוש. 876 01:13:57,130 --> 01:13:59,800 הנה זה אומר נקודתי מצב הטיעון למחרוזת 877 01:13:59,800 --> 01:14:01,930 מתחיל עם אחד מהרצפים הבאים. 878 01:14:01,930 --> 01:14:06,480 אז r, קובץ טקסט פתוח לקריאה. זה מה שאנחנו רוצים לעשות. 879 01:14:08,930 --> 01:14:13,210 לקריאה, ואני רוצה לשמור את זה. 880 01:14:13,210 --> 01:14:18,720 הדבר הולך להיות * קובץ. עכשיו מה שאני רוצה לעשות? 881 01:14:18,720 --> 01:14:21,200 תן לי שני. 882 01:14:28,140 --> 01:14:30,430 אוקיי. עכשיו מה שאני רוצה לעשות? 883 01:14:30,430 --> 01:14:32,940 [תלמיד] בדקו אם זה NULL. >> [אודן] כן. 884 01:14:32,940 --> 01:14:38,690 בכל פעם שאתה פותח את קובץ, ודא שאתה בהצלחה תוכל לפתוח אותו. 885 01:14:58,930 --> 01:15:10,460 >> עכשיו אני רוצה לעשות את הדברים האלה termios בו אני רוצה לקרוא את ההגדרות הנוכחיות שלי 1 886 01:15:10,460 --> 01:15:14,050 ולשמור אותם לתוך משהו, אז אני רוצה לשנות את ההגדרות שלי 887 01:15:14,050 --> 01:15:19,420 לזרוק כל תו שאני מקליד, 888 01:15:19,420 --> 01:15:22,520 ואז אני רוצה לעדכן את ההגדרות הללו. 889 01:15:22,520 --> 01:15:27,250 ואז בסוף התכנית, אני רוצה לחזור להגדרות המקוריות שלי. 890 01:15:27,250 --> 01:15:32,080 אז struct הולך להיות מהסוג termios, ואני הולך לרוצה שניים מאלה. 891 01:15:32,080 --> 01:15:35,600 הראשון הולך להיות current_settings, 892 01:15:35,600 --> 01:15:42,010 ואז הם הולכים להיות hacker_settings. 893 01:15:42,010 --> 01:15:48,070 ראשית, אני הולך ברצונך לשמור את ההגדרות הנוכחיות שלי, 894 01:15:48,070 --> 01:15:53,790 אז אני הולך לרוצה לעדכן hacker_settings, 895 01:15:53,790 --> 01:16:01,570 ולאחר מכן דרך בסוף התכנית שלי, אני רוצה לחזור להגדרות נוכחיות. 896 01:16:01,570 --> 01:16:08,660 אז שמירת הגדרות נוכחיות, אופן שבו עובד, אנחנו termios אדם. 897 01:16:08,660 --> 01:16:15,810 אנו רואים שיש לנו tcsetattr זה int, int tcgetattr. 898 01:16:15,810 --> 01:16:22,960 אני עובר בtermios struct ידי המצביע שלו. 899 01:16:22,960 --> 01:16:30,640 כך ייראו הוא - רצינות, כבר שכחה מה הפונקציה נקראה. 900 01:16:30,640 --> 01:16:34,930 להעתיק ולהדביק אותו. 901 01:16:39,150 --> 01:16:45,500 אז tcgetattr, אז אני רוצה לעבור בstruct שאני חוסך במידע, 902 01:16:45,500 --> 01:16:49,650 שהולך להיות current_settings, 903 01:16:49,650 --> 01:16:59,120 וטענתו הראשונה היא מתארת ​​קובץ לדבר אני רוצה להציל את התכונות של. 904 01:16:59,120 --> 01:17:04,360 מה הוא מתאר הקובץ היא כמו כל פעם שתפתח את קובץ, הוא מקבל מתאר קובץ. 905 01:17:04,360 --> 01:17:14,560 כשfopen argv [1], הוא מקבל מתאר קובץ שאתה התייחסות 906 01:17:14,560 --> 01:17:16,730 כל פעם שאתה רוצה לקרוא או לכתוב אליו. 907 01:17:16,730 --> 01:17:19,220 זה לא מתאר קובץ שאני רוצה להשתמש כאן. 908 01:17:19,220 --> 01:17:21,940 ישנם שלושה מתארי קובץ שיש לך כברירת מחדל, 909 01:17:21,940 --> 01:17:24,310 שהנם סטנדרט ב, את התקן, ושגיאה סטנדרטית. 910 01:17:24,310 --> 01:17:29,960 כברירת מחדל, אני חושב שזה סטנדרט בהוא 0, פלט הסטנדרטי הוא 1, ושגיאה סטנדרטית היא 2. 911 01:17:29,960 --> 01:17:33,980 אז מה אני רוצה לשנות את ההגדרות של? 912 01:17:33,980 --> 01:17:37,370 אני רוצה לשנות את ההגדרות של כל פעם שאני מכה אופי, 913 01:17:37,370 --> 01:17:41,590 אני רוצה שזה זורק את האופי שבמקום להדפיס אותו על המסך. 914 01:17:41,590 --> 01:17:45,960 מה זרם - סטנדרטי ב, מתוך סטנדרטיים, או שגיאה סטנדרטית - 915 01:17:45,960 --> 01:17:52,050 מגיב לדברים כשאני מקליד במקלדת? >> [תלמיד] תקן פנימה >> כן. 916 01:17:52,050 --> 01:17:56,450 אז או שאני יכול לעשות 0 או שאני יכול לעשות stdin. 917 01:17:56,450 --> 01:17:59,380 אני מקבל current_settings של תקן פנימה 918 01:17:59,380 --> 01:18:01,720 >> עכשיו אני רוצה לעדכן את ההגדרות הללו, 919 01:18:01,720 --> 01:18:07,200 אז קודם אני אעתיק לhacker_settings מה current_settings שלי. 920 01:18:07,200 --> 01:18:10,430 ואיך עבודת structs היא שזה יהיה פשוט להעתיק. 921 01:18:10,430 --> 01:18:14,510 זה מעתיק את כל השדות, כפי שהיית מצפה. 922 01:18:14,510 --> 01:18:17,410 >> עכשיו אני רוצה לעדכן חלק מהשדות. 923 01:18:17,410 --> 01:18:21,670 כאשר מסתכלים על termios, היית צריך לקרוא את זה הרבה 924 01:18:21,670 --> 01:18:24,110 רק כדי לראות מה שאתה רוצה לחפש, 925 01:18:24,110 --> 01:18:28,210 אבל את הדגלים שאתה הולך רוצה לחפש הם הד, 926 01:18:28,210 --> 01:18:33,110 כך ECHO תווי קלט אקו. 927 01:18:33,110 --> 01:18:37,710 ראשית אני רוצה להגדיר - רצינות, כבר שכח מה את השדות. 928 01:18:45,040 --> 01:18:47,900 זה מה שנראה כמו struct. 929 01:18:47,900 --> 01:18:51,060 אז מצבי קלט אני חושב שאנחנו רוצים לשנות. 930 01:18:51,060 --> 01:18:54,210 אנחנו נסתכל על הפתרון כדי לוודא שזה מה שאנחנו רוצים לשנות. 931 01:19:04,060 --> 01:19:12,610 אנחנו רוצים לשנות את lflag כדי למנוע צורך להסתכל דרך כל אלה. 932 01:19:12,610 --> 01:19:14,670 אנחנו רוצים לשנות את המצבים מקומיים. 933 01:19:14,670 --> 01:19:17,710 היית צריך לקרוא את כל הדבר הזה כדי להבין איפה הכל משייכת 934 01:19:17,710 --> 01:19:19,320 כי אנחנו רוצים לשנות. 935 01:19:19,320 --> 01:19:24,120 אבל זה חלק פנימי של מצבים מקומיים לאן אנחנו הולכים רוצים לשנות את זה. 936 01:19:27,080 --> 01:19:33,110 אז hacker_settings.cc_lmode הוא מה זה נקרא. 937 01:19:39,630 --> 01:19:43,020 c_lflag. 938 01:19:49,060 --> 01:19:52,280 זה המקום בו אנו נכנסים למפעילים סיביים האופרטור. 939 01:19:52,280 --> 01:19:54,860 אנחנו סוג של מחוץ לזמן, אבל אנחנו עוברים את זה ממש מהר. 940 01:19:54,860 --> 01:19:56,600 זה המקום בו אנו נכנסים למפעילים סיביים האופרטור, 941 01:19:56,600 --> 01:19:59,950 שבו אני חושב שאמרתי פעם אחת לפני זמן רב כי בכל פעם שאתה מתחיל להתמודד עם דגלים, 942 01:19:59,950 --> 01:20:03,370 אתה הולך להיות באמצעות סיבי האופרטור מפעיל הרבה. 943 01:20:03,370 --> 01:20:08,240 כל ביט בדגל מתאים לסוג מסוים של התנהגות. 944 01:20:08,240 --> 01:20:14,090 אז הנה, את הדגל הזה יש חבורה של דברים שונים, שבו כולם מתכוונים למשהו אחר. 945 01:20:14,090 --> 01:20:18,690 אבל מה שאני רוצה לעשות הוא פשוט לכבות את החלק שמתאים לECHO. 946 01:20:18,690 --> 01:20:25,440 אז כדי להפוך את זה שאני עושה את & = ¬ ECHO. 947 01:20:25,440 --> 01:20:30,110 למעשה, אני חושב שזה כמו tECHO או משהו. אני רק הולך לבדוק שוב. 948 01:20:30,110 --> 01:20:34,050 אני יכול termios. זה פשוט ECHO. 949 01:20:34,050 --> 01:20:38,440 ECHO הולך להיות קצת בודד. 950 01:20:38,440 --> 01:20:44,230 ¬ ECHO הולך אומר כל הביטים מוגדרים 1, מה שאומר שכל הדגלים מוגדרים נכון 951 01:20:44,230 --> 01:20:47,140 פרט לקצת ההד. 952 01:20:47,140 --> 01:20:53,830 על ידי סיום הדגלים המקומיים שלי עם זה, זה אומר שכל הדגלים שכרגע מוגדרים נכון 953 01:20:53,830 --> 01:20:56,520 עדיין יהיה מוגדר נכון. 954 01:20:56,520 --> 01:21:03,240 אם דגל ECHO מוגדר נכון, אז זה מוגדר בהכרח כוזב על דגל ECHO. 955 01:21:03,240 --> 01:21:07,170 אז שורת קוד הזאת פשוט מכבה את דגל ECHO. 956 01:21:07,170 --> 01:21:16,270 בשורות האחרות בקוד, אני פשוט להעתיק אותם בעניין של זמן ואז להסביר אותם. 957 01:21:27,810 --> 01:21:30,180 בפתרון, הוא אמר 0. 958 01:21:30,180 --> 01:21:33,880 זה בטח יותר טוב לומר במפורש stdin. 959 01:21:33,880 --> 01:21:42,100 >> שים לב שאני גם עושה ECHO | ICANON כאן. 960 01:21:42,100 --> 01:21:46,650 ICANON מתייחס למשהו נפרד, מה שאומר שמצב קנונים. 961 01:21:46,650 --> 01:21:50,280 מה זה אומר מצב קנונים הוא בדרך כלל כשאתה מקליד את שורת הפקודה, 962 01:21:50,280 --> 01:21:54,670 סטנדרטי באינו מעבד כל דבר עד שתגיעי לשורה חדשה. 963 01:21:54,670 --> 01:21:58,230 אז מתי אתה GetString, אתה מקליד חבורה של דברים, אז אתה מכה שורה חדשה. 964 01:21:58,230 --> 01:22:00,590 זה, כאשר הם נשלחים לסטנדרטיים פנימה 965 01:22:00,590 --> 01:22:02,680 זה ברירת המחדל. 966 01:22:02,680 --> 01:22:05,830 כשאני מכבה את מצב קנונים, עכשיו כל תו בודד שתלחץ 967 01:22:05,830 --> 01:22:10,910 מה שגורם לעיבוד, שהיא בדרך כלל סוג של רע, כי זה איטי לעבד את הדברים האלה, 968 01:22:10,910 --> 01:22:14,330 וזה למה זה טוב להצפתו לקווים שלמים. 969 01:22:14,330 --> 01:22:16,810 אבל אני רוצה שכל תו להיות מעובד 970 01:22:16,810 --> 01:22:18,810 מאז אני לא רוצה אותו שיחכה לי להכות שורה חדשה 971 01:22:18,810 --> 01:22:21,280 לפני שהוא מעבד את כל הדמויות שאני מקליד. 972 01:22:21,280 --> 01:22:24,760 זה מבטל את מצב קנונים. 973 01:22:24,760 --> 01:22:31,320 החומר הזה פשוט אומר כאשר הוא בעצם מעבד תווים. 974 01:22:31,320 --> 01:22:35,830 משמעות הדבר הוא לעבד אותם באופן מיידי, ברגע שאני מקליד אותם, לעבד אותם. 975 01:22:35,830 --> 01:22:42,510 וזה התפקיד שהוא מעדכן את ההגדרות שלי לסטנדרט ב, 976 01:22:42,510 --> 01:22:45,480 ואמצעי TCSA לעשות את זה עכשיו. 977 01:22:45,480 --> 01:22:50,310 האפשרויות האחרות הן לחכות עד שכל מה שהוא כיום בזרם המעובד. 978 01:22:50,310 --> 01:22:52,030 זה לא ממש משנה. 979 01:22:52,030 --> 01:22:56,920 רק עכשיו לשנות את ההגדרות שלי להיות כל מה שנמצא כרגע בhacker_typer_settings. 980 01:22:56,920 --> 01:23:02,210 אני מניח שקראתי לזה hacker_settings, אז בואו נשנה את זה. 981 01:23:09,610 --> 01:23:13,500 לשנות הכל כדי hacker_settings. 982 01:23:13,500 --> 01:23:16,870 >> עכשיו בסוף התכנית שלנו שאנחנו הולכים ברצונך לחזור 983 01:23:16,870 --> 01:23:20,210 למה עכשיו בתוך normal_settings, 984 01:23:20,210 --> 01:23:26,560 שהוא הולך רק כדי להיראות כמו & normal_settings. 985 01:23:26,560 --> 01:23:30,650 שים לב שלא השתניתי כל normal_settings מאז מקבל אותו במקור. 986 01:23:30,650 --> 01:23:34,520 אז רק כדי לשנות אותם בחזרה, אני עובר אותם בחזרה בסוף. 987 01:23:34,520 --> 01:23:38,390 זה היה העדכון. אוקיי. 988 01:23:38,390 --> 01:23:43,900 >> עכשיו בתוך מכאן אני פשוט להסביר את הקוד בעניין של זמן. 989 01:23:43,900 --> 01:23:46,350 זה לא כל כך הרבה קוד. 990 01:23:50,770 --> 01:24:03,750 אנו רואים אנו קוראים תווים מהקובץ. אנחנו קראנו לזה f. 991 01:24:03,750 --> 01:24:07,850 עכשיו אתה יכול הגבר fgetc, אבל איך fgetc הוא הולך לעבוד 992 01:24:07,850 --> 01:24:11,910 הוא פשוט שזה הולך לחזור הדמות שאתה פשוט לקרוא או EOF, 993 01:24:11,910 --> 01:24:15,680 אשר מתאים לסוף הקובץ או התרחשות כלשהי שגיאה. 994 01:24:15,680 --> 01:24:19,900 אנו מתעקלים, ממשיכים לקרוא תו בודד מהקובץ, 995 01:24:19,900 --> 01:24:22,420 עד שנגמרנו לנו תווים לקריאה. 996 01:24:22,420 --> 01:24:26,650 ואם אנחנו כבר עושים את זה, אנחנו מחכים בתו בודד מתקן פנימה 997 01:24:26,650 --> 01:24:29,090 בכל פעם שאתה מקליד משהו בשורת הפקודה, 998 01:24:29,090 --> 01:24:32,820 שקוראים בתווי תקן מפנימה 999 01:24:32,820 --> 01:24:38,330 אז putchar רק הולך לשים char אנו קוראים מכאן לקובץ פלט סטנדרטי. 1000 01:24:38,330 --> 01:24:42,890 אתה יכול אדם putchar, אבל זה רק עושה לסטנדרטי החוצה, זה שמדפיס אופי. 1001 01:24:42,890 --> 01:24:51,600 אתה גם יכול לעשות printf ("% c", ג); אותו רעיון. 1002 01:24:53,330 --> 01:24:56,670 זה הולך לעשות את חלק הארי של העבודה שלנו. 1003 01:24:56,670 --> 01:25:00,300 >> הדבר האחרון שאנחנו הולכים רוצים לעשות הוא פשוט fclose הקובץ שלנו. 1004 01:25:00,300 --> 01:25:03,310 אם אינך fclose, זה דליפת זיכרון. 1005 01:25:03,310 --> 01:25:06,680 אנחנו רוצים fclose הקובץ שנפתחנו במקור, ואני חושב שזה זה. 1006 01:25:06,680 --> 01:25:13,810 אם אנחנו עושים את זה, כבר יש לי בעיות. 1007 01:25:13,810 --> 01:25:17,260 בואו נראים. 1008 01:25:17,260 --> 01:25:19,960 מה זה להתלונן? 1009 01:25:19,960 --> 01:25:30,220 צפוי "int", אבל טענה הוא מסוג 'struct _IO_FILE *'. 1010 01:25:36,850 --> 01:25:39,370 נצטרך לראות אם זה עובד. 1011 01:25:45,210 --> 01:25:53,540 מותר אך ורק בC99. Augh. אוקיי, תעשה hacker_typer. 1012 01:25:53,540 --> 01:25:57,760 עכשיו אנחנו מקבלים הסבר שימושי יותר. 1013 01:25:57,760 --> 01:25:59,900 אז שימוש במזהה לא מוצהרת "normal_settings '. 1014 01:25:59,900 --> 01:26:04,170 אני לא קורא לזה normal_settings. אני קראתי לזה current_settings. 1015 01:26:04,170 --> 01:26:12,090 אז בואו לשנות את כל זה. 1016 01:26:17,920 --> 01:26:21,710 כעת עובר ויכוח. 1017 01:26:26,290 --> 01:26:29,500 אני אעשה 0 זה לעת עתה. 1018 01:26:29,500 --> 01:26:36,720 אוקיי. . / Hacker_typer cp.c. 1019 01:26:36,720 --> 01:26:39,590 אני גם לא לנקות את המסך בהתחלה. 1020 01:26:39,590 --> 01:26:42,960 אבל אתה יכול להסתכל אחורה לסדרת הבעיה האחרונה כדי לראות איך לנקות את המסך. 1021 01:26:42,960 --> 01:26:45,160 זה פשוט מדפיס כמה תווים 1022 01:26:45,160 --> 01:26:47,210 בזמן הזה היא עושה את מה שאני רוצה לעשות. 1023 01:26:47,210 --> 01:26:48,900 אוקיי. 1024 01:26:48,900 --> 01:26:55,280 וחשבתי למה זה צריך להיות 0 במקום stdin, 1025 01:26:55,280 --> 01:27:00,560 שיש להגדיר # 0, 1026 01:27:00,560 --> 01:27:03,890 זה מתלונן ש-- 1027 01:27:13,150 --> 01:27:19,360 לפני כשאמרתי שיש מתארי קובץ אבל אז יש לך גם * הקובץ שלך, 1028 01:27:19,360 --> 01:27:23,210 מתאר קובץ הוא רק מספר שלם אחד, 1029 01:27:23,210 --> 01:27:26,970 בעוד * קובץ יש חבורה שלמה של דברים הקשורים אליו. 1030 01:27:26,970 --> 01:27:30,380 הסיבה שאנחנו צריכים לומר 0 במקום stdin 1031 01:27:30,380 --> 01:27:37,480 הוא stdin שהוא * קובץ שמצביע על הדבר שהוא התייחסות מתארת ​​קובץ 0. 1032 01:27:37,480 --> 01:27:45,070 אז גם כאן כאשר אני עושה fopen (argv [1], אני מקבל * קובץ בחזרה. 1033 01:27:45,070 --> 01:27:51,180 אבל אי שם שב* הקובץ הוא דבר מתאים למתאר הקובץ לקובץ זה. 1034 01:27:51,180 --> 01:27:57,430 אם אתה מסתכל על הדף פתוח לאדם, ולכן אני חושב שאתה צריך לעשות אדם 3 פתוחים - nope - 1035 01:27:57,430 --> 01:27:59,380 גבר 2 פתוחים - כן. 1036 01:27:59,380 --> 01:28:06,250 אם אתה מסתכל על הדף לפתוח, פתוח הוא כמו fopen ברמה נמוכה יותר, 1037 01:28:06,250 --> 01:28:09,350 וזה חוזר מתאר קובץ בפועל. 1038 01:28:09,350 --> 01:28:12,050 fopen עושה כל מיני דברים בראש הפתוח, 1039 01:28:12,050 --> 01:28:17,640 שבמקום לחזור רק שמתאר קובץ מחזיר קובץ שלם * מצביע 1040 01:28:17,640 --> 01:28:20,590 בתוכה הוא מתאר הקובץ הקטן שלנו. 1041 01:28:20,590 --> 01:28:25,020 אז סטנדרטי במתייחס לדבר * הקובץ, 1042 01:28:25,020 --> 01:28:29,120 ואילו 0 מתייחסים רק סטנדרטי מתאר קובץ בעצמו. 1043 01:28:29,120 --> 01:28:32,160 >> שאלות? 1044 01:28:32,160 --> 01:28:35,930 [צוחק] השתולל. 1045 01:28:35,930 --> 01:28:39,140 בסדר. אנחנו נעשינו. [צוחק] 1046 01:28:39,140 --> 01:28:42,000 >> [CS50.TV]