1 00:00:00,000 --> 00:00:02,520 [Powered by Google Translate] [סעיף 4 - יותר נוח] 2 00:00:02,520 --> 00:00:04,850 [רוב אודן - אוניברסיטת הרווארד] 3 00:00:04,850 --> 00:00:07,370 [זה CS50. - CS50.TV] 4 00:00:08,920 --> 00:00:13,350 יש לנו מחר חידון, במקרה שאתם לא יודעים את זה. 5 00:00:14,810 --> 00:00:20,970 זה בעצם על כל מה שיכל לראות בכיתה או היית צריך לראות אותו בכיתה. 6 00:00:20,970 --> 00:00:26,360 הכולל מצביעים, למרות שהם נושא מאוד לאחרונה. 7 00:00:26,360 --> 00:00:29,860 אתה צריך לפחות להבין את הרמות הגבוהות שלהם. 8 00:00:29,860 --> 00:00:34,760 כל דבר שנעלם מעל בכיתה אתה צריך להבין לחידון. 9 00:00:34,760 --> 00:00:37,320 אז אם יש לך שאלות עליהם, אתה יכול לשאול אותם עכשיו. 10 00:00:37,320 --> 00:00:43,280 אבל זה הולך להיות מפגש מאוד של הסטודנט שבו אתם שואלים שאלות, 11 00:00:43,280 --> 00:00:45,060 כך אני מקווה, לאנשים יש שאלות. 12 00:00:45,060 --> 00:00:48,020 למישהו יש שאלות? 13 00:00:49,770 --> 00:00:52,090 כן. >> [תלמיד] האם אתה הולך על מצביעים שוב? 14 00:00:52,090 --> 00:00:54,350 אני מתכוון לעבור על מצביעים. 15 00:00:54,350 --> 00:00:59,180 כל המשתנים שלך בהכרח לחיות בזיכרון, 16 00:00:59,180 --> 00:01:04,450 אבל בדרך כלל אתה לא לדאוג בקשר לזה ואתה פשוט אומר x ו-y + 2 + 3 17 00:01:04,450 --> 00:01:07,080 והמהדר להבין איפה הדברים חיים בשבילך. 18 00:01:07,080 --> 00:01:12,990 ברגע שאתה מתעסק עם מצביעים, עכשיו אתה משתמש באופן מפורש כתובות זיכרון אלו. 19 00:01:12,990 --> 00:01:19,800 אז משתנה אחד תהיה יחיד שגרים בכתובת אחת בכל זמן נתון. 20 00:01:19,800 --> 00:01:24,040 אם אנחנו רוצים להצהיר מצביע, מה הסוג הולך להיראות כמו? 21 00:01:24,040 --> 00:01:26,210 >> אני רוצה להכריז עמ מצביע. מה הסוג נראה לך? 22 00:01:26,210 --> 00:01:33,530 [תלמיד] int * p. >> כן. אז int * p. 23 00:01:33,530 --> 00:01:38,030 ואיך אני עושה את זה מצביע על x? >> [תלמיד] אמפרסנד. 24 00:01:40,540 --> 00:01:45,300 [אודן] אז אמפרסנד נקרא פשוטו כמשמעו, את כתובתו של מפעיל. 25 00:01:45,300 --> 00:01:50,460 לכן, כאשר אני אומר & x זה מקבל את כתובת הזיכרון של משתנה. 26 00:01:50,460 --> 00:01:56,790 אז עכשיו יש לי p המצביע, ובכל מקום בקוד שלי אני יכול להשתמש * p 27 00:01:56,790 --> 00:02:02,960 או שאני יכול להשתמש x וזה יהיה בדיוק אותו דבר. 28 00:02:02,960 --> 00:02:09,520 (* P). מה זה עושה? מה כוכב שאומר? 29 00:02:09,520 --> 00:02:13,120 זה [תלמיד] פירושו ערך בנקודה זו. >> כן. 30 00:02:13,120 --> 00:02:17,590 אז אם אנחנו מסתכלים על זה, זה יכול להיות מאוד שימושי כדי לצייר את התרשימים 31 00:02:17,590 --> 00:02:22,230 שבו זה קופסה קטנה של זיכרון עבור x, שקורית לי ערך 4, 32 00:02:22,230 --> 00:02:25,980 אז יש לנו קופסה קטנה של זיכרון עבור p, 33 00:02:25,980 --> 00:02:31,590 וכך p מצביע לx, אז אנו מפנים את חץ מ-p ל-x. 34 00:02:31,590 --> 00:02:40,270 לכן, כאשר אנו אומרים * p אנחנו אומרים ללכת לתיבה שהיא p. 35 00:02:40,270 --> 00:02:46,480 כוכב הוא לעקוב אחרי החץ ולאחר מכן לעשות מה שאתה רוצה שבתיבה ממש שם. 36 00:02:46,480 --> 00:03:01,090 אז אני יכול לומר * p = 7, ושילך לתיבה שהיא x ושינוי שעד 7. 37 00:03:01,090 --> 00:03:13,540 או שאני יכול לומר int z = * p * 2; זה מבלבל, כי כוכב זה, כוכב. 38 00:03:13,540 --> 00:03:19,230 כוכב אחד הוא ביטול הפנית p, הכוכב השני הוא הכפלה פי 2. 39 00:03:19,230 --> 00:03:26,780 שים לב שיכול להיות מוחלף ע '* באותה מידה עם x. 40 00:03:26,780 --> 00:03:29,430 אתה יכול להשתמש בם באותה הדרך. 41 00:03:29,430 --> 00:03:38,000 ואז בשלב מאוחר יותר יכול להיות לי נקודה p למשהו חדש לגמרי. 42 00:03:38,000 --> 00:03:42,190 אני רק יכול לומר p = &z; 43 00:03:42,190 --> 00:03:44,940 אז עכשיו p ללא נקודות ארוכות יותר לx; הוא מצביע על z. 44 00:03:44,940 --> 00:03:50,510 וכל פעם שאני עושה * p שזה אותו הדבר כמו לעשות z. 45 00:03:50,510 --> 00:03:56,170 אז הדבר השימושי על זה ברגע שנתחיל להיכנס לפונקציות. 46 00:03:56,170 --> 00:03:59,790 >> זה סוג של טעם להכריז על מצביע שזה מצביע משהו 47 00:03:59,790 --> 00:04:03,140 ואז אתה פשוט ביטול הפניה זה 48 00:04:03,140 --> 00:04:06,060 כאשר אתה יכול להשתמש במשתנה המקורית מלכתחילה. 49 00:04:06,060 --> 00:04:18,190 אבל כאשר אתה מקבל לתוך פונקציות - אז נגיד שיש לנו תפקיד כלשהו, ​​int foo, 50 00:04:18,190 --> 00:04:32,810 שלוקח את מצביע ופשוט עושה * p = 6; 51 00:04:32,810 --> 00:04:39,990 כמו שראינו קודם עם החלפה, אתה לא יכול לעשות החלפה יעילה ופונקציה נפרדת 52 00:04:39,990 --> 00:04:45,180 רק על ידי מספרים שלמים, כי הכל עובר בC תמיד עובר ליד ערך. 53 00:04:45,180 --> 00:04:48,360 גם כאשר אתה עובר מצביעים שאתה עובר ליד ערך. 54 00:04:48,360 --> 00:04:51,940 זה פשוט כל כך קורה כי ערכים אלה הם כתובות זיכרון. 55 00:04:51,940 --> 00:05:00,770 לכן, כאשר אני אומר foo (p); אני מעביר את המצביע לפונקצית foo 56 00:05:00,770 --> 00:05:03,910 ואז הוא עושה foo * p = 6; 57 00:05:03,910 --> 00:05:08,600 אז בתוך הפונקציה ש, * p הוא עדיין שווה הערך ל x, 58 00:05:08,600 --> 00:05:12,720 אבל אני לא יכול להשתמש בחלק פנימי של x שהפונקציה כי זה לא scoped בתוך פונקציה. 59 00:05:12,720 --> 00:05:19,510 אז * p = 6 הם הדרך היחידה שאני יכול לגשת למשתנה מקומית מפונקציה אחרת. 60 00:05:19,510 --> 00:05:23,600 או, כן, מצביעים הם הדרך היחידה שאני יכול לגשת למשתנה מקומית מפונקציה אחרת. 61 00:05:23,600 --> 00:05:31,600 [תלמיד] בואו נגיד שאתה רוצה לחזור מצביע. איך בדיוק אתה עושה את זה? 62 00:05:31,600 --> 00:05:44,270 [אודן] תשואת מצביע כבמשהו כמו int y = 3; תשואה & y? >> [תלמיד] כן. 63 00:05:44,270 --> 00:05:48,480 [אודן] אוקיי. אתה לא צריך לעשות את זה. זה רע. 64 00:05:48,480 --> 00:05:59,480 אני חושב שראיתי בשקופיות הרצאות אלה שהתחלת לראות את כל תרשים זה של זיכרון 65 00:05:59,480 --> 00:06:02,880 שבו עד כאן יש לך את הכתובת בזיכרון 0 66 00:06:02,880 --> 00:06:09,550 וכאן יש לך 4 הופעות כתובת זיכרון או 2 עד 32. 67 00:06:09,550 --> 00:06:15,120 אז יש לך כמה דברים ועוד כמה דברים ואז יש לך ערימה שלך 68 00:06:15,120 --> 00:06:21,780 ויש לך ערימה שלך, שאתה רק התחלת ללמוד על, גדלת. 69 00:06:21,780 --> 00:06:24,390 [תלמיד] האם לא הערימה מעל לערימה? 70 00:06:24,390 --> 00:06:27,760 >> כן. הערימה היא בראש, לא? >> [תלמיד] ובכן, הוא הכניס 0 על גבי. 71 00:06:27,760 --> 00:06:30,320 [תלמיד] הו, הוא הכניס 0 על גבי. >> [תלמיד] אה, בסדר. 72 00:06:30,320 --> 00:06:36,060 הצהרה: כל מקום עם CS50 אתה הולך לראות את זה ככה. >> [תלמיד] אוקיי. 73 00:06:36,060 --> 00:06:40,290 זה רק שכשאתה רואה ערימות ראשונה, 74 00:06:40,290 --> 00:06:45,000 אוהב כשאתה חושב על ערימה אתה חושב על דברים לערום על גבי זו. 75 00:06:45,000 --> 00:06:50,810 אז אנחנו נוטים להפוך את זה סביב כך הערימה גדלה כמו ערימה כרגיל 76 00:06:50,810 --> 00:06:55,940 במקום הערימה משתלשל מטה. >> [תלמיד] לא ערימות טכניות לגדול מדי, אם כי? 77 00:06:55,940 --> 00:07:01,100 זה תלוי במה אתה מתכוון בתגדל. 78 00:07:01,100 --> 00:07:04,010 המחסנית והערימה תמיד לגדול בכיוונים מנוגדים. 79 00:07:04,010 --> 00:07:09,420 ערימה תמיד גדלה בתחושה שהיא גדלה 80 00:07:09,420 --> 00:07:12,940 כיוון כתובות גבוהות יותר זיכרון, והערימה הולכות וגדלה למטה 81 00:07:12,940 --> 00:07:17,260 בכך שהוא גדל לכיוון כתובות זיכרון נמוכות יותר. 82 00:07:17,260 --> 00:07:20,250 כך שהחלק העליון הוא 0 והתחתון הוא כתובות זיכרון גבוהה. 83 00:07:20,250 --> 00:07:26,390 הם גדלו וגדלו, רק בכיוונים מנוגדים. 84 00:07:26,390 --> 00:07:29,230 [תלמיד] אני פשוט התכוונתי שבגלל שאמרת לך לשים בתחתית ערימה 85 00:07:29,230 --> 00:07:33,640 כי זה נראה יותר אינטואיטיבי, כי לערימה כדי להתחיל בראש ערימה, 86 00:07:33,640 --> 00:07:37,520 הערימה של מעל עצמו יותר מדי, אז כלומר - >> כן. 87 00:07:37,520 --> 00:07:44,960 ניתן גם לחשוב על הערימה כגדל ויותר גדולים, אבל יותר מכך המחסנית. 88 00:07:44,960 --> 00:07:50,280 אז הערימה היא כזאת שאנחנו סוג של רוצים להראות שגדלו. 89 00:07:50,280 --> 00:07:55,390 אבל בכל מקום אתה מסתכל אחרת הוא הולך להראות את הכתובה 0 בראש 90 00:07:55,390 --> 00:07:59,590 ואת כתובת הזיכרון הגבוהה ביותר בתחתית, אז זה הנוף הרגיל שלך זיכרון. 91 00:07:59,590 --> 00:08:02,100 >> האם יש לך שאלה? 92 00:08:02,100 --> 00:08:04,270 [תלמיד] אתה יכול לספר לנו יותר על הגל? 93 00:08:04,270 --> 00:08:06,180 כן. אני אגיע לזה בשנייה. 94 00:08:06,180 --> 00:08:12,220 ראשית, יחזור למה חוזר & y הוא דבר רע, 95 00:08:12,220 --> 00:08:18,470 במחסנית יש לך חבורה של מסגרות ערימה המייצגות את כל הפונקציות 96 00:08:18,470 --> 00:08:20,460 שכבר קרא. 97 00:08:20,460 --> 00:08:27,990 אז התעלמות דברים קודמים, החלק העליון של הערימה שלך תמיד תהיה הפונקציה העיקרית 98 00:08:27,990 --> 00:08:33,090 מכיוון שזה התפקיד הראשון שהוא נקרא. 99 00:08:33,090 --> 00:08:37,130 ואז כשאתה קורא לפונקציה אחרת, הערימה הולכת לגדול במורד. 100 00:08:37,130 --> 00:08:41,640 אז אם אני קורא באיזה אירוע, foo, והיא מקבלת מסגרתו של המחסנית, 101 00:08:41,640 --> 00:08:47,280 הוא יכול להתקשר לתפקיד כלשהו, ​​בר, היא מקבלת מסגרתו של המחסנית. 102 00:08:47,280 --> 00:08:49,840 והבר יכול להיות רקורסיבית וזה יכול לקרוא לעצמו, 103 00:08:49,840 --> 00:08:54,150 וכדי ששיחה שנייה לברים הוא הולך לקבל מסגרתו של המחסנית. 104 00:08:54,150 --> 00:08:58,880 וכך מה שקורה במסגרות מחסנית אלה הם כל המשתנים המקומיים 105 00:08:58,880 --> 00:09:03,450 ואת כל טענות פונקציה ש-- 106 00:09:03,450 --> 00:09:08,730 כל דברים שהם באופן מקומי scoped לתפקיד זה ללכת במסגרות מחסנית אלה. 107 00:09:08,730 --> 00:09:21,520 אז זה אומר שכשאמרתי משהו כמו בר הוא פונקציה, 108 00:09:21,520 --> 00:09:29,270 אני רק הולך להכריז על מספר שלם ולאחר מכן לחזור למצביע שהמספר השלם. 109 00:09:29,270 --> 00:09:33,790 אז איפה זה y לחיות? 110 00:09:33,790 --> 00:09:36,900 [התלמיד] y מתגורר בבר. >> [אודן] כן. 111 00:09:36,900 --> 00:09:45,010 אי שם בריבוע קטן זה של זיכרון הוא ריבוע קטן יותר כי יש y בזה. 112 00:09:45,010 --> 00:09:53,370 כשאני חוזר & y, אני מחזיר מצביע לגוש הקטן של זיכרון. 113 00:09:53,370 --> 00:09:58,400 אבל אז כאשר חוזר לתפקד, מסגרתה מקבלת הערימה התפגרה המחסנית. 114 00:10:01,050 --> 00:10:03,530 וזה למה קורא לערימה. 115 00:10:03,530 --> 00:10:06,570 זה כמו במבנה נתוני המחסנית, אם אתה יודע מה זה. 116 00:10:06,570 --> 00:10:11,580 או אפילו כמו ערימה של מגשים תמיד הדוגמא, 117 00:10:11,580 --> 00:10:16,060 העיקרי היא הולך על הקרקעית, אז הפונקציה הראשונה שאתה קורא הולכת ללכת על גבי זה, 118 00:10:16,060 --> 00:10:20,400 ואתה לא יכול לחזור לעיקרי עד שתחזור מכל הפונקציות שכבר נקראו 119 00:10:20,400 --> 00:10:22,340 שהונח על גבי זה. 120 00:10:22,340 --> 00:10:28,650 >> [תלמיד] אז אם אתה עשית לחזור & y, הערך שכפוף לשינוי ללא הודעה מוקדמת. 121 00:10:28,650 --> 00:10:31,290 כן, זהו - >> [תלמיד] זה יכול להיות מוחלף. >> כן. 122 00:10:31,290 --> 00:10:34,660 זה לגמרי - אם אתה מנסה ו-- 123 00:10:34,660 --> 00:10:38,040 זו תהיה גם בר * int כי זה חוזר מצביע, 124 00:10:38,040 --> 00:10:41,310 כך סוג החזרתו הוא * int. 125 00:10:41,310 --> 00:10:46,500 אם תנסה להשתמש בערך ההחזרה של פונקציה זו, זה התנהגות לא מוגדרת 126 00:10:46,500 --> 00:10:51,770 כי המצביע שמצביע על זיכרון רע. >> [תלמיד] אוקיי. 127 00:10:51,770 --> 00:11:01,250 אז מה אם, למשל, אתה הכרזת int * y = malloc (sizeof (int))? 128 00:11:01,250 --> 00:11:03,740 זה יותר טוב. כן. 129 00:11:03,740 --> 00:11:07,730 [תלמיד] דברנו על זה שאנחנו גוררים את הדברים לסל המחזור שלנו 130 00:11:07,730 --> 00:11:11,750 הם לא באמת נמחקו, אנחנו פשוט מאבדים את המצביעים שלהם. 131 00:11:11,750 --> 00:11:15,550 אז במקרה הזה אין לנו בעצם למחוק את הערך או שזה עדיין שם בזיכרון? 132 00:11:15,550 --> 00:11:19,130 על פי רוב, זה הולך עדיין להיות שם. 133 00:11:19,130 --> 00:11:24,220 אבל בואו נאמר שקורים לי להתקשר כמה תפקיד אחר, באז. 134 00:11:24,220 --> 00:11:28,990 באז הוא הולך לקבל מסגרתו של המחסנית בפה. 135 00:11:28,990 --> 00:11:31,470 זה הולך להיות להחליף את כל הדברים האלה, 136 00:11:31,470 --> 00:11:34,180 ואז, אם כך לנסות ולהשתמש במצביע שקבלת בעבר, 137 00:11:34,180 --> 00:11:35,570 זה לא הולך להיות אותו הערך. 138 00:11:35,570 --> 00:11:38,150 זה הולך השתנה רק בגלל שקראת באז הפונקציה. 139 00:11:38,150 --> 00:11:43,080 [תלמיד] אבל, אם אנחנו לא, האם היינו עדיין לקבל 3? 140 00:11:43,080 --> 00:11:44,990 [אודן] סביר להניח, שהיית עושה. 141 00:11:44,990 --> 00:11:49,670 אבל אתה לא יכול לסמוך על זה. C פשוט אומר התנהגות לא מוגדרת. 142 00:11:49,670 --> 00:11:51,920 >> [תלמיד] הו, היא עושה. אוקיי. 143 00:11:51,920 --> 00:11:58,190 לכן, כאשר אתה רוצה לחזור מצביע, זה המקום שבי malloc מגיע בשימוש. 144 00:12:00,930 --> 00:12:15,960 אני כותב בעצם רק לחזור malloc (3 * sizeof (int)). 145 00:12:17,360 --> 00:12:24,050 אנחנו נעבור על malloc יותר בשנייה, אבל הרעיון של malloc הוא כל המשתנים המקומיים שלך 146 00:12:24,050 --> 00:12:26,760 תמיד הולכים במחסנית. 147 00:12:26,760 --> 00:12:31,570 כל הדבר שהוא malloced ממשיך ערמה, וזה לנצח, ותמיד יהיה בערימה 148 00:12:31,570 --> 00:12:34,490 עד שתשחרר אותה באופן מפורש. 149 00:12:34,490 --> 00:12:42,130 אז זה אומר שכשמשהו שאתה malloc, זה הולך לשרוד לאחר שחוזר לתפקד. 150 00:12:42,130 --> 00:12:46,800 [תלמיד] האם זה ישרוד לאחר התכנית מפסיקה לרוץ? מספר >> 151 00:12:46,800 --> 00:12:53,180 אוקיי, אז זה הולך להיות שם עד שהתכנית עברה את כל הדרך עשתה בריצה. >> כן. 152 00:12:53,180 --> 00:12:57,510 אנחנו יכולים לעבור על פרטים של מה קורה כאשר התכנית מפסיקה לרוץ. 153 00:12:57,510 --> 00:13:02,150 ייתכן שתצטרך להזכיר לי, אבל זה דבר שונה לגמרי. 154 00:13:02,150 --> 00:13:04,190 [תלמיד] אז malloc יוצר מצביע? >> כן. 155 00:13:04,190 --> 00:13:13,030 Malloc - >> [תלמיד] אני חושב malloc מייעד גוש הזיכרון שמצביע יכול להשתמש. 156 00:13:15,400 --> 00:13:19,610 [אודן] אני רוצה תרשים זה שוב. >> [תלמיד] אז פונקציה זו עובדת, אם כי? 157 00:13:19,610 --> 00:13:26,430 [תלמיד] כן, malloc מייעד גוש הזיכרון שאתה יכול להשתמש בו, 158 00:13:26,430 --> 00:13:30,470 ואז זה מחזיר את הכתובת של הבלוק הראשון של הזיכרון הזה. 159 00:13:30,470 --> 00:13:36,750 >> [אודן] כן. לכן, כאשר אתם malloc, אתה תופס איזה בלוק של זיכרון 160 00:13:36,750 --> 00:13:38,260 זה כרגע בערימה. 161 00:13:38,260 --> 00:13:43,040 אם הערימה קטנה מדי, אז הערימה היא רק הולכת לגדול, והוא גדל בכיוון זה. 162 00:13:43,040 --> 00:13:44,650 אז תניח הערימה קטנה מדי. 163 00:13:44,650 --> 00:13:49,960 אז זה עומד לגדול קצת ולחזור מצביע לבלוק הזה שרק גדל. 164 00:13:49,960 --> 00:13:55,130 כאשר דברים בחינם, אתה עושה יותר מקום בערמה, 165 00:13:55,130 --> 00:14:00,030 כן אז מאוחר קורא לmalloc יכול לעשות שימוש חוזר בזיכרון שכבר שוחרר בעבר. 166 00:14:00,030 --> 00:14:09,950 הדבר החשוב על malloc וחופשי הוא שזה נותן לך שליטה מלאה 167 00:14:09,950 --> 00:14:12,700 במשך החיים של גושי הזיכרון הללו. 168 00:14:12,700 --> 00:14:15,420 משתנים גלובליים הם תמיד בחיים. 169 00:14:15,420 --> 00:14:18,500 משתנה מקומי חיים בתוך הטווח שלהם. 170 00:14:18,500 --> 00:14:22,140 ברגע שאתה עובר על פני סד מתולתל, המשתנים המקומיים מתים. 171 00:14:22,140 --> 00:14:28,890 זכרון Malloced חי כשאתה רוצה שהוא יהיה בחיים 172 00:14:28,890 --> 00:14:33,480 ולאחר מכן הוא שוחרר כשאתה אומר לו להשתחרר. 173 00:14:33,480 --> 00:14:38,420 אלה הם למעשה רק 3 סוגים של זיכרון, באמת. 174 00:14:38,420 --> 00:14:41,840 יש ניהול זיכרון אוטומטי, המהווה את המחסנית. 175 00:14:41,840 --> 00:14:43,840 דברים קורים לך באופן אוטומטי. 176 00:14:43,840 --> 00:14:46,910 כשאתה אומר x int, זיכרון מוקצה עבור x int. 177 00:14:46,910 --> 00:14:51,630 כאשר x יוצא מחוץ לתחום, זיכרון הוא קולח עבור x. 178 00:14:51,630 --> 00:14:54,790 אז יש ניהול דינמי זיכרון, וזה מה שmalloc הוא, 179 00:14:54,790 --> 00:14:56,740 וזה כאשר יש לך שליטה. 180 00:14:56,740 --> 00:15:01,290 אתה דינמי להחליט מתי זיכרון צריך ולא צריך להיות מוקצה. 181 00:15:01,290 --> 00:15:05,050 ואז יש סטטי, שרק אומר שהוא חי לנצח, 182 00:15:05,050 --> 00:15:06,610 וזה מה שמשתנה גלובלי הם. 183 00:15:06,610 --> 00:15:10,240 הם פשוט תמיד בזיכרון. 184 00:15:10,960 --> 00:15:12,760 >> שאלות? 185 00:15:14,490 --> 00:15:17,230 [תלמיד] אתה יכול להגדיר בלוק רק באמצעות סוגריים מסולסלים 186 00:15:17,230 --> 00:15:21,220 אבל לא שיש לי אם הצהרה או הצהרה בזמן או משהו כזה? 187 00:15:21,220 --> 00:15:29,130 באפשרותך להגדיר בלוק כמו בפונקציה, אבל שיש סוגריים מסולסלים מדי. 188 00:15:29,130 --> 00:15:32,100 [תלמיד] אז אתה לא יכול פשוט להיות כמו זוג אקראי של סוגריים מסולסלים בקוד שלך 189 00:15:32,100 --> 00:15:35,680 כי יש משתנים מקומיים? >> כן, אתה יכול. 190 00:15:35,680 --> 00:15:45,900 בתוך בר int שנהיה לנו {int y = 3;}. 191 00:15:45,900 --> 00:15:48,440 זה אמור להיות ממש כאן. 192 00:15:48,440 --> 00:15:52,450 אבל זה לחלוטין מגדיר את היקף int y. 193 00:15:52,450 --> 00:15:57,320 לאחר שהסד 2 המתולתל, y לא ניתן להשתמש יותר. 194 00:15:57,910 --> 00:16:00,630 למרות שאתה כמעט אף פעם לא עושה את זה,. 195 00:16:02,940 --> 00:16:07,370 אם אחזור למה שקורה כאשר תכנית מסתיימת, 196 00:16:07,370 --> 00:16:18,760 יש סוג של שקר טעות / חצי שאנו נותנים במטרה רק כדי לעשות את הדברים קלים יותר. 197 00:16:18,760 --> 00:16:24,410 אנחנו אומרים לך שכאשר אתה להקצות זיכרון 198 00:16:24,410 --> 00:16:29,860 אתה הקצאת חלק הנתח של זכרון RAM לאותו משתנה. 199 00:16:29,860 --> 00:16:34,190 אבל אתה לא באמת נוגע ישירות RAM אי פעם בתוכניות שלך. 200 00:16:34,190 --> 00:16:37,490 אם אתה חושב על זה, איך אני ציירתי - 201 00:16:37,490 --> 00:16:44,330 ובעצם, אם אתה עובר בGDB תראה אותו דבר. 202 00:16:51,120 --> 00:16:57,590 לא משנה כמה פעמים אתה מפעיל התכנית שלך או מה תכנית שאתה מפעיל, 203 00:16:57,590 --> 00:16:59,950 המחסנית תמיד עומדת להתחיל - 204 00:16:59,950 --> 00:17:06,510 אתה תמיד הולך לראות משהו משתנה סביב oxbffff כתובת. 205 00:17:06,510 --> 00:17:09,470 זה בדרך כלל אי ​​שם באזור זה. 206 00:17:09,470 --> 00:17:18,760 אבל איך 2 תוכניות אולי יכולות להיות מצביעים לאותו הזיכרון? 207 00:17:20,640 --> 00:17:27,650 [תלמיד] יש כמה ייעוד שרירותי של איפה oxbfff אמור להיות בזכרון RAM 208 00:17:27,650 --> 00:17:31,320 שבעצם יכול להיות במקומות שונים בהתאם כאשר הפונקציה נקראה. 209 00:17:31,320 --> 00:17:35,920 כן. מונח זיכרון וירטואלי. 210 00:17:35,920 --> 00:17:42,250 הרעיון הוא שכל תהליך יחיד, כל תכנית יחידה שבו פועלת במחשב שלך 211 00:17:42,250 --> 00:17:49,450 יש משלה - נניח 32 סיביים - כתובת החלל עצמאי לחלוטין. 212 00:17:49,450 --> 00:17:51,590 זה מרחב הכתובות. 213 00:17:51,590 --> 00:17:56,220 יש לה 4 ג'יגה העצמאית לחלוטין לשימוש. 214 00:17:56,220 --> 00:18:02,220 >> אז אם אתה מפעיל 2 תוכניות בו זמנית, תכנית זו רואה 4 ג'יגה לעצמו, 215 00:18:02,220 --> 00:18:04,870 תכנית זו רואה 4 ג'יגה לעצמו, 216 00:18:04,870 --> 00:18:07,720 ואי אפשר שתכנית זו dereference מצביע 217 00:18:07,720 --> 00:18:10,920 וסופו של דבר עם זיכרון מתכנית זו. 218 00:18:10,920 --> 00:18:18,200 ומה זיכרון וירטואלי הוא הוא מיפוי ממרחב כתובות תהליכים 219 00:18:18,200 --> 00:18:20,470 לדברים ממשיים בזכרון RAM. 220 00:18:20,470 --> 00:18:22,940 כך שזה תלוי במערכת ההפעלה שלך כדי לדעת את זה, 221 00:18:22,940 --> 00:18:28,080 היי, כשoxbfff מצביע זה הבחור dereferences, זה באמת אומר 222 00:18:28,080 --> 00:18:31,040 שהוא רוצה RAM ייט 1000, 223 00:18:31,040 --> 00:18:38,150 ואילו אם oxbfff dereferences תכנית זו, שהוא באמת רוצה זכרון RAM ייט 10000. 224 00:18:38,150 --> 00:18:41,590 הם יכולים להיות רחוקים אחד מהשני באופן שרירותי. 225 00:18:41,590 --> 00:18:48,730 זה נכון אפילו לגבי דברים בתוך מרחב כתובות תהליכים בודד. 226 00:18:48,730 --> 00:18:54,770 אז כמו שהוא רואה את כל 4 ג'יגה לעצמו, אבל בואו יגיד - 227 00:18:54,770 --> 00:18:57,290 [תלמיד] האם כל תהליך אחד - 228 00:18:57,290 --> 00:19:01,350 בואו נגיד שיש לך מחשב עם רק 4 גיגהבייט של זכרון RAM. 229 00:19:01,350 --> 00:19:06,430 האם כל תהליך יחיד לראות את 4 ג'יגה השלמה? >> כן. 230 00:19:06,430 --> 00:19:13,060 אבל 4 ג'יגה היא רואה היא שקר. 231 00:19:13,060 --> 00:19:20,460 זה פשוט שהוא חושב שיש את כל הזיכרון הזה כי הוא לא יודע שום תהליך אחר קיים. 232 00:19:20,460 --> 00:19:28,140 זה יהיה להשתמש רק כזיכרון כמה שזה באמת צריך. 233 00:19:28,140 --> 00:19:32,340 מערכת ההפעלה היא לא הולכת לתת לזכרון RAM לתהליך זה 234 00:19:32,340 --> 00:19:35,750 אם הוא לא משתמש בכל זיכרון בכל האזור הזה. 235 00:19:35,750 --> 00:19:39,300 זה לא הולך לתת לו זיכרון עבור אזור זה. 236 00:19:39,300 --> 00:19:54,780 אבל הרעיון הוא ש-- אני מנסה לחשוב על - אני לא יכול לחשוב על אנלוגיה. 237 00:19:54,780 --> 00:19:56,780 אנלוגיות הן קשות. 238 00:19:57,740 --> 00:20:02,700 אחת הסוגיות של זיכרון וירטואלי או אחד מהדברים שזה פתרון 239 00:20:02,700 --> 00:20:06,810 הוא שתהליכים צריכים להיות לגמרי לא מודעים לזה. 240 00:20:06,810 --> 00:20:12,140 ואז אתה יכול לכתוב כל תכנית שרק dereferences כל מצביע, 241 00:20:12,140 --> 00:20:19,340 רוצים פשוט לכתוב תכנית שאומרת * (ox1234), 242 00:20:19,340 --> 00:20:22,890 ושהכתובת של ביטול הפנית זכרון 1234. 243 00:20:22,890 --> 00:20:28,870 >> אבל זה תלוי במערכת ההפעלה ואז לתרגם את מה ש1234 אמצעים. 244 00:20:28,870 --> 00:20:33,960 אז אם 1234 קורים להיות כתובת זיכרון תקף לתהליך זה, 245 00:20:33,960 --> 00:20:38,800 כמו שזה בערימה או משהו, אז זה יחזיר את הערך של כתובת זיכרון 246 00:20:38,800 --> 00:20:41,960 ככל התהליך יודע. 247 00:20:41,960 --> 00:20:47,520 אבל אם 1234 אינן כתובת חוקית, כמו שזה קורה לנחות 248 00:20:47,520 --> 00:20:52,910 באיזו חלקה קטנה של זיכרון כאן שהיא מעבר לערימה ומעבר לערימה 249 00:20:52,910 --> 00:20:57,200 ואתה לא ממש נצלת את זה, אז זה כאשר אתה מקבל דברים כמו segfaults 250 00:20:57,200 --> 00:21:00,260 בגלל שאתה נוגע בזיכרון שאתה לא צריך להיות נוגע ללב. 251 00:21:07,180 --> 00:21:09,340 זה נכון גם - 252 00:21:09,340 --> 00:21:15,440 מערכה 32-bit, 32 סיביות אומרת שאתה צריך 32 ביטים כדי להגדיר כתובת זיכרון. 253 00:21:15,440 --> 00:21:22,970 זאת הסיבה שהמצביעים הם 8 בתים כי 32 ביטים הם 8 בתים - או 4 בתים. 254 00:21:22,970 --> 00:21:25,250 מצביעים הם 4 בתים. 255 00:21:25,250 --> 00:21:33,680 אז כשאתה רואה את סמן כמו oxbfffff, כלומר - 256 00:21:33,680 --> 00:21:40,080 בתוך כל תכנית נתנה לך פשוט יכול לבנות כל מצביע שרירותי, 257 00:21:40,080 --> 00:21:46,330 בכל מקום מox0 ל8 f's השור - FFFFFFFF. 258 00:21:46,330 --> 00:21:49,180 [תלמיד] לא אמרו שהם 4 בתים? >> כן. 259 00:21:49,180 --> 00:21:52,730 [תלמיד] ואז כל בית יהיה - >> [אודן] הקסדצימאלי. 260 00:21:52,730 --> 00:21:59,360 הקסאדצימלי - 5, 6, 7, 8. אז מצביעים שאתה הולך לראות תמיד בהקסדצימלי. 261 00:21:59,360 --> 00:22:01,710 זה רק איך אנו מסווגים מצביעים. 262 00:22:01,710 --> 00:22:05,240 כל 2 ספרות של הקסדצימלי היא בית 1. 263 00:22:05,240 --> 00:22:09,600 אז הנה הולך להיות 8 ספרות הקסדצימליים עבור 4 בתים. 264 00:22:09,600 --> 00:22:14,190 אז כל מצביע בודד על מערכה 32-bit הולך להיות 4 בתים, 265 00:22:14,190 --> 00:22:18,550 מה שאומר שבתהליך שלך אתה יכול לבנות את כל 4 בתים שרירותיים 266 00:22:18,550 --> 00:22:20,550 ולהפוך את מצביע מחוץ לזה, 267 00:22:20,550 --> 00:22:32,730 מה שאומר שככל שזה מודע, זה יכול לתת מענה לכל 2 ל32 הבתים של זיכרון. 268 00:22:32,730 --> 00:22:34,760 למרות שזה לא ממש יש גישה לזה, 269 00:22:34,760 --> 00:22:40,190 גם אם המחשב שלך יש 512 מגה בייט בלבד, הוא חושב שיש כל כך הרבה זיכרון. 270 00:22:40,190 --> 00:22:44,930 ומערכת ההפעלה היא חכמה מספיק שזה יהיה להקצות רק את מה שאתה באמת צריך. 271 00:22:44,930 --> 00:22:49,630 זה לא פשוט ללכת, הו, תהליך חדש: 4 הופעות. 272 00:22:49,630 --> 00:22:51,930 >> כן. >> [תלמיד] מה השור מתכוון? למה אתה כותב את זה? 273 00:22:51,930 --> 00:22:54,980 זה רק הסמל להקסדצימלי. 274 00:22:54,980 --> 00:22:59,590 כשאתה רואה את התחלה עם מספר שור, הדברים הרצופים הם הקסדצימלי. 275 00:23:01,930 --> 00:23:05,760 [תלמיד] היית להסביר על מה קורה כאשר תכנית מסתיימת. >> כן. 276 00:23:05,760 --> 00:23:09,480 מה קורה כאשר תכנית מסתיימת הוא מערכת ההפעלה 277 00:23:09,480 --> 00:23:13,600 פשוט מחק את המיפויים שיש לה לכתובות אלה, וזהו זה. 278 00:23:13,600 --> 00:23:17,770 מערכת ההפעלה עכשיו יכולה פשוט לתת לזיכרון שלתכנית אחרת לשימוש. 279 00:23:17,770 --> 00:23:19,490 [תלמיד] אוקיי. 280 00:23:19,490 --> 00:23:24,800 לכן, כאשר אתה מקצה משהו על הערימה או משתני המחסנית או כל דבר או גלובליים, 281 00:23:24,800 --> 00:23:27,010 כולם פשוט ייעלמו ברגע שהתכנית מסתיימת 282 00:23:27,010 --> 00:23:32,120 מכיוון שמערכת ההפעלה היא עכשיו חופשיה לתת זיכרון לכל תהליך אחר. 283 00:23:32,120 --> 00:23:35,150 [תלמיד] למרות שיש כנראה עדיין ערכים שנכתבו ב? >> כן. 284 00:23:35,150 --> 00:23:37,740 הערכים צפויים עדיין שם. 285 00:23:37,740 --> 00:23:41,570 זה פשוט שזה הולך להיות קשה להגיע אליהם. 286 00:23:41,570 --> 00:23:45,230 זה הרבה יותר קשה להגיע אליהם, מאשר לקבל בקובץ שנמחק 287 00:23:45,230 --> 00:23:51,450 בגלל סוג הקובץ שנמחק מיושב שם במשך זמן רב ואת הכונן הקשיח הוא הרבה יותר גדול. 288 00:23:51,450 --> 00:23:54,120 אז זה הולך להחליף חלקים שונים של זיכרון 289 00:23:54,120 --> 00:23:58,640 לפני שזה קורה כדי לדרוס את הנתח של זיכרון שהקובץ שהיה אמור להיות בו. 290 00:23:58,640 --> 00:24:04,520 אבל זיכרון ראשי, זיכרון RAM, לעבור הרבה יותר מהר, 291 00:24:04,520 --> 00:24:08,040 אז זה הולך מהר מאוד להיות מוחלף. 292 00:24:10,300 --> 00:24:13,340 שאלות על זה או כל דבר אחר? 293 00:24:13,340 --> 00:24:16,130 [תלמיד] יש לי שאלות על נושא אחר. >> אוקיי. 294 00:24:16,130 --> 00:24:19,060 האם יש למישהו שאלות על זה? 295 00:24:20,170 --> 00:24:23,120 >> אוקיי. נושא אחר. >> [תלמיד] אוקיי. 296 00:24:23,120 --> 00:24:26,550 עובר עליי כמה מהבדיקות בפועל, 297 00:24:26,550 --> 00:24:30,480 ובאחד מהם הוא מדבר על sizeof 298 00:24:30,480 --> 00:24:35,630 ואת הערך שהיא מחזירה או סוגים שונים משתנים. >> כן. 299 00:24:35,630 --> 00:24:45,060 והוא אמר שגם int וארוכה גם יחד תשואת 4, כך שהם עוד שני 4 הבתים. 300 00:24:45,060 --> 00:24:48,070 האם יש הבדל בין int וארוך, או שזה אותו הדבר? 301 00:24:48,070 --> 00:24:50,380 כן, יש הבדל. 302 00:24:50,380 --> 00:24:52,960 C הסטנדרטי - 303 00:24:52,960 --> 00:24:54,950 אני כנראה הולך לעשות בלגן. 304 00:24:54,950 --> 00:24:58,800 C הסטנדרטי הוא בדיוק כמו מה C הוא, התיעוד הרשמי של ג 305 00:24:58,800 --> 00:25:00,340 זה מה שזה אומר. 306 00:25:00,340 --> 00:25:08,650 אז C הסטנדרטי פשוט אומר שchar לנצח ותמיד יהיה בית 1. 307 00:25:10,470 --> 00:25:19,040 כל מה שאחרי - קצר היא תמיד רק הוגדר כגדול או שווה ל char. 308 00:25:19,040 --> 00:25:23,010 זה עשוי להיות בהחלט יותר מאשר, אבל לא חיובי. 309 00:25:23,010 --> 00:25:31,940 Int הוא פשוט מוגדר כגדול או שווה לקצר. 310 00:25:31,940 --> 00:25:36,210 והוא ממש הגדיר עוד להיות גדול או שווה ל int. 311 00:25:36,210 --> 00:25:41,600 ועוד ארוכים הוא גדול או שווה לזמן רב. 312 00:25:41,600 --> 00:25:46,610 אז הדבר היחיד C הסטנדרטי מגדיר הוא סדר היחסי של כל דבר. 313 00:25:46,610 --> 00:25:54,880 הסכום בפועל של זכרון דברים שהוא בדרך כלל לקחת עד יישום, 314 00:25:54,880 --> 00:25:57,640 אבל זה מוגדר די טוב בשלב זה. >> [תלמיד] אוקיי. 315 00:25:57,640 --> 00:26:02,490 אז מכנסיים קצרים כמעט תמיד הולכים להיות 2 בתים. 316 00:26:04,920 --> 00:26:09,950 Ints כמעט תמיד הולך להיות 4 בתים. 317 00:26:12,070 --> 00:26:15,340 משתוקק ארוך כמעט תמיד הולכים להיות 8 בתים. 318 00:26:17,990 --> 00:26:23,160 ומתגעגע, זה תלוי אם אתה משתמש 32-bit או 64-bit מערכת. 319 00:26:23,160 --> 00:26:27,450 אז עוד הולך מתאימים לסוג של מערכת. 320 00:26:27,450 --> 00:26:31,920 אם אתה משתמש במערכת 32-bit כמו המכשיר, זה הולך להיות 4 בתים. 321 00:26:34,530 --> 00:26:42,570 אם אתה משתמש ב 64-bit כמו הרבה מחשבים האחרונים, זה הולך להיות 8 בתים. 322 00:26:42,570 --> 00:26:45,230 >> Ints הם כמעט תמיד 4 בתים בשלב זה. 323 00:26:45,230 --> 00:26:47,140 משתוקק ארוך הם כמעט תמיד 8 בתים. 324 00:26:47,140 --> 00:26:50,300 בעבר, ints פעם היה רק ​​2 בתים. 325 00:26:50,300 --> 00:26:56,840 אבל שם לב שזה עומד בכל היחסים האלה של יותר מ ושווים לחלוטין. 326 00:26:56,840 --> 00:27:01,280 כל עוד מותר בהחלט להיות באותו הגודל כמו מספר שלם, 327 00:27:01,280 --> 00:27:04,030 וזה גם אפשר להיות באותו הגודל כמו זמן ארוך. 328 00:27:04,030 --> 00:27:11,070 וזה פשוט כל כך קורה להיות שב99.999% ממערכות, שזה הולך להיות שווה 329 00:27:11,070 --> 00:27:15,800 או int או ארוך ארוך. זה פשוט תלוי ב32-bit או 64-bit. >> [תלמיד] אוקיי. 330 00:27:15,800 --> 00:27:24,600 בצף, איך היא הנקודה העשרונית המיועדת במונחים של ביטים? 331 00:27:24,600 --> 00:27:27,160 אוהב כמו בינארי? >> כן. 332 00:27:27,160 --> 00:27:30,570 אתה לא צריך לדעת את זה לCS50. 333 00:27:30,570 --> 00:27:32,960 אתה אפילו לא לומד את זה בשנת 61. 334 00:27:32,960 --> 00:27:37,350 אתה לא לומד את זה באמת בכל קורס. 335 00:27:37,350 --> 00:27:42,740 זה רק ייצוג. 336 00:27:42,740 --> 00:27:45,440 אני שוכח את הקצבאות הסיביות המדויקות. 337 00:27:45,440 --> 00:27:53,380 הרעיון של נקודה צפה הוא שאתה להקצות מספר מסוים של ביטים לייצג - 338 00:27:53,380 --> 00:27:56,550 בעיקרון, כל מה שהוא בייצוג מדעי. 339 00:27:56,550 --> 00:28:05,600 אז אתה להקצות מספר מסוים של ביטים כדי לייצג את המספר עצמו, כמו 1.2345. 340 00:28:05,600 --> 00:28:10,200 אני לא יכול לייצג את מספר בספרות של יותר מ 5. 341 00:28:12,200 --> 00:28:26,300 ואז אתה גם להקצות מספר מסוים של ביטים כך שהוא נוטה להיות כמו 342 00:28:26,300 --> 00:28:32,810 אתה רק יכול ללכת עד למספר מסוים, כמו זה המעריך הגדול ביותר שאתה יכול להיות, 343 00:28:32,810 --> 00:28:36,190 ואתה יכול לרדת רק למעריך מסוים, 344 00:28:36,190 --> 00:28:38,770 רוצה שהמעריך הקטן ביותר שאתה יכול לקבל. 345 00:28:38,770 --> 00:28:44,410 >> אני לא זוכר את קטעי הדרך המדויקות מוקצים לכל הערכים הללו, 346 00:28:44,410 --> 00:28:47,940 אך מספר מסוים של ביטים מוקדשים ל1.2345, 347 00:28:47,940 --> 00:28:50,930 עוד מספר מסוים של ביטים מוקדשים לפרשן, 348 00:28:50,930 --> 00:28:55,670 וזה אפשרי רק כדי לייצג את מעריך בגודל מסוים. 349 00:28:55,670 --> 00:29:01,100 [תלמיד] וכפול? האם זה כמו מצוף ארוך במיוחד? >> כן. 350 00:29:01,100 --> 00:29:07,940 זה אותו הדבר כמו לצוף רק שעכשיו אתה בתים של 8 במקום 4 בתים. 351 00:29:07,940 --> 00:29:11,960 כעת תוכל להשתמש ב9 ספרות או 10 ספרות, 352 00:29:11,960 --> 00:29:16,630 וזה יהיה מסוגל ללכת עד 300 במקום 100. >> [תלמיד] אוקיי. 353 00:29:16,630 --> 00:29:21,550 ומרחף גם 4 בתים. >> כן. 354 00:29:21,550 --> 00:29:27,520 ובכן, שוב, זה כנראה תלוי ביישום כולל כללי, 355 00:29:27,520 --> 00:29:30,610 אבל צף הם 4 בתים, זוגות הם 8. 356 00:29:30,610 --> 00:29:33,440 זוגות נקראים כפול משום שהם כפולים בגודל של מצופים. 357 00:29:33,440 --> 00:29:38,380 [תלמיד] אוקיי. ויש פעמים שמכפילים? >> יש שלא. 358 00:29:38,380 --> 00:29:43,660 אני חושב - >> [תלמיד] כמו משתוקק ארוך? >> כן. לא נראה לי. כן. 359 00:29:43,660 --> 00:29:45,950 [תלמיד] במבחן של השנה שעברה לא הייתה שאלה לגבי הפונקציה העיקרית 360 00:29:45,950 --> 00:29:49,490 צורך להיות חלק מהתכנית שלך. 361 00:29:49,490 --> 00:29:52,310 התשובה הייתה שזה לא צריך להיות חלק מהתכנית שלך. 362 00:29:52,310 --> 00:29:55,100 באיזה מצב? זה מה שראיתי. 363 00:29:55,100 --> 00:29:59,090 [אודן] נראה - >> [תלמיד] מה מצב? 364 00:29:59,090 --> 00:30:02,880 האם יש לך בעיה? >> [תלמיד] כן, אני בהחלט יכול למשוך אותו. 365 00:30:02,880 --> 00:30:07,910 זה לא חייב להיות, מבחינה טכנית, אבל בעיקרון זה הולך להיות. 366 00:30:07,910 --> 00:30:10,030 [תלמיד] ראיתי אחד בשנה של שונה. 367 00:30:10,030 --> 00:30:16,220 זה היה כמו אמת או שקר: חוקי - >> אה, קובץ c.? 368 00:30:16,220 --> 00:30:18,790 . [תלמיד] כל קובץ c צריך להיות - [גם כשדבר בפעם אחת - לא מובן] 369 00:30:18,790 --> 00:30:21,120 אוקיי. אז זה נפרד. 370 00:30:21,120 --> 00:30:26,800 >> . קובץ c פשוט צריך להכיל פונקציות. 371 00:30:26,800 --> 00:30:32,400 אתה יכול לקמפל קובץ לתוך קוד מכונה, בינארי, שיהיה, 372 00:30:32,400 --> 00:30:36,620 זה בלי שיהיה הפעלה עדיין. 373 00:30:36,620 --> 00:30:39,420 הפעלה תקפה חייבת להיות פונקציה עיקרית. 374 00:30:39,420 --> 00:30:45,460 אתה יכול לכתוב 100 פונקציות בקובץ 1 אבל לא עיקרית 375 00:30:45,460 --> 00:30:48,800 ולאחר מכן לאסוף את שלינארי, 376 00:30:48,800 --> 00:30:54,460 אז אתה כותב קובץ אחר שיש רק מלך אלא שהיא ממכנת חבורה של פונקציות אלה 377 00:30:54,460 --> 00:30:56,720 בקובץ בינארי הזה כאן. 378 00:30:56,720 --> 00:31:01,240 ולכן כאשר אתה עושה הפעלה, זה מה שעושה המקשר 379 00:31:01,240 --> 00:31:05,960 הוא שהוא משלב 2 קבצים בינאריים אלה להפעלה. 380 00:31:05,960 --> 00:31:11,400 אז. קובץ c לא צריך להיות פונקציה עיקרית בכלל. 381 00:31:11,400 --> 00:31:19,220 ועל בסיס קוד גדול שתראה אלף. קבצי C וקבצים עיקריים 1. 382 00:31:23,960 --> 00:31:26,110 עוד שאלות? 383 00:31:29,310 --> 00:31:31,940 [תלמיד] הייתה שאלה אחרת. 384 00:31:31,940 --> 00:31:36,710 זה אומר לעשות הוא מהדר. אמת או שקר? 385 00:31:36,710 --> 00:31:42,030 והתשובה הייתה שקרי, והבנתי למה זה לא כמו קלאנג. 386 00:31:42,030 --> 00:31:44,770 אבל מה שאנחנו קוראים לעשות אם זה לא? 387 00:31:44,770 --> 00:31:49,990 הפוך הוא בעצם רק - אני יכול לראות בדיוק מה שהיא ממכנת אותו. 388 00:31:49,990 --> 00:31:52,410 אבל זה פשוט מפעיל פקוד. 389 00:31:53,650 --> 00:31:55,650 הפוך. 390 00:31:58,240 --> 00:32:00,870 אני יכול למשוך את זה. כן. 391 00:32:10,110 --> 00:32:13,180 אה, כן. הפוך גם עושה את זה. 392 00:32:13,180 --> 00:32:17,170 זה אומר, שהמטרה של כלי האיפור היא לקבוע באופן אוטומטי 393 00:32:17,170 --> 00:32:19,610 שחתיכות של תכנית גדולה צריכות להיות recompiled 394 00:32:19,610 --> 00:32:22,350 ולהוציא את הפקודות להדר אותם. 395 00:32:22,350 --> 00:32:27,690 אתה יכול לעשות להפוך את קבצים שנמצאים ממש ענקים. 396 00:32:27,690 --> 00:32:33,210 הפוך מסתכל על חותמות הזמן של קבצים, וכמו שאמרנו קודם, 397 00:32:33,210 --> 00:32:36,930 אתה יכול לקמפל את קבצים בודדים, וזה לא עד שתגיע למקשר 398 00:32:36,930 --> 00:32:39,270 שהם ביחד להפעלה. 399 00:32:39,270 --> 00:32:43,810 אז אם יש לך 10 קבצים שונים וביצוע שינוי עד 1 מתוכם, 400 00:32:43,810 --> 00:32:47,870 אז מה עושה, היא הולכת לעשות הוא פשוט קומפילציה שקובץ 1 401 00:32:47,870 --> 00:32:50,640 ולאחר מכן לקשר מחדש את הכל ביחד. 402 00:32:50,640 --> 00:32:53,020 אבל זה הרבה יותר מטומטם מזה. 403 00:32:53,020 --> 00:32:55,690 זה תלוי בך כדי להגדיר לגמרי שזה מה שצריך לעשות. 404 00:32:55,690 --> 00:32:59,560 זה כברירת מחדל יש את היכולת לזהות חומר חותמת הזמן הזה, 405 00:32:59,560 --> 00:33:03,220 אבל אתה יכול לכתוב קובץ לעשות כדי לעשות משהו. 406 00:33:03,220 --> 00:33:09,150 אתה יכול לכתוב להפוך את הקובץ, כך שכאשר אתה מקליד לעשות את זה רק תקליטורים לספרייה אחרת. 407 00:33:09,150 --> 00:33:15,560 אני היה מתוסכל כי אני כל טקטיקה הפנימית של המכשיר שלי 408 00:33:15,560 --> 00:33:21,740 ואז אני רואה את ה-PDF מהמק. 409 00:33:21,740 --> 00:33:30,720 >> אז אני הולך לFinder ואני יכול לעשות לך, להתחבר לשרת, 410 00:33:30,720 --> 00:33:36,950 והשרת שאני מתחבר למכשיר הוא שלי, ואז אני פותח את ה-PDF 411 00:33:36,950 --> 00:33:40,190 שמקבל שהוכן על ידי LaTeX. 412 00:33:40,190 --> 00:33:49,320 אבל אני היה מתוסכל, כי בכל פעם שהייתי צריך לרענן את ה-PDF, 413 00:33:49,320 --> 00:33:53,900 הייתי צריך להעתיק אותו לספרייה מסוימת שזה יכול לגשת 414 00:33:53,900 --> 00:33:57,710 וזה אהיה מעצבן. 415 00:33:57,710 --> 00:34:02,650 אז במקום זה כתב קובץ לעשות, שיש לך להגדיר איך הוא עושה את הדברים. 416 00:34:02,650 --> 00:34:06,130 איך אתה עושה את זה בפורמט PDF-LaTeX. 417 00:34:06,130 --> 00:34:10,090 בדיוק כמו כל קובץ אחר לעשות - או שאני מניח שאתה לא ראית את הקבצים לעשות, 418 00:34:10,090 --> 00:34:13,510 אבל יש לנו במכשיר קובץ יצרן עולמי שרק אומר, 419 00:34:13,510 --> 00:34:16,679 אם אתה מקים קובץ C, השתמש קלאנג. 420 00:34:16,679 --> 00:34:20,960 וכן כאן בקובץ המעשה שלי שאני עושה אני אומר, 421 00:34:20,960 --> 00:34:25,020 זה קובץ שאתה הולך רוצה לקמפל עם PDF-LaTeX. 422 00:34:25,020 --> 00:34:27,889 ואז זה LaTeX PDF שעושה קומפילציה. 423 00:34:27,889 --> 00:34:31,880 הפכו לא הידור. זה פשוט פועל בפקודות אלה ברצף שצוינתי. 424 00:34:31,880 --> 00:34:36,110 אז הוא פועל LaTeX-PDF, הוא מעתיק אותו לספרייה אני רוצה שזה יועתק ל, 425 00:34:36,110 --> 00:34:38,270 תקליטור זה לספרייה ועושה דברים אחרים, 426 00:34:38,270 --> 00:34:42,380 אך כל שהיא עושה הוא לזהות כאשר שינויים בקבצים, 427 00:34:42,380 --> 00:34:45,489 ואם היא משתנית, אז זה יהיה להפעיל את הפקודות שהוא אמור לרוץ 428 00:34:45,489 --> 00:34:48,760 כאשר השינויים בקבצים. >> [תלמיד] אוקיי. 429 00:34:50,510 --> 00:34:54,420 אני לא יודע איפה את הקבצים להפוך את העולם הם בשבילי כדי לבדוק את זה. 430 00:34:57,210 --> 00:35:04,290 שאלות אחרות? שום דבר מהעבר חידונים? כל דברים מצביעים? 431 00:35:06,200 --> 00:35:08,730 יש דברים עדינים עם מצביעים כמו - 432 00:35:08,730 --> 00:35:10,220 אני לא הולך להיות מסוגל למצוא שאלת חידון על זה - 433 00:35:10,220 --> 00:35:16,250 אבל בדיוק כמו שדברים מהסוג הזה. 434 00:35:19,680 --> 00:35:24,060 ודא שאתה מבין, שכאשר אני אומר int * x * y - 435 00:35:24,890 --> 00:35:28,130 זה לא בדיוק משהו כאן, אני מניח. 436 00:35:28,130 --> 00:35:32,140 אבל כמו * x * y, אלה 2 משתנים שנמצאים במחסנית. 437 00:35:32,140 --> 00:35:37,220 כשאני אומר x = malloc (sizeof (int)), x הוא עדיין משתנה במחסנית, 438 00:35:37,220 --> 00:35:41,180 malloc היא קצת מעל בלוק בערימה, ואנחנו מנהלים נקודת x לערימה. 439 00:35:41,180 --> 00:35:43,900 >> אז משהו על נקודתי המחסנית לערימה. 440 00:35:43,900 --> 00:35:48,100 בכל פעם שכל דבר שאתה malloc, אתה בהכרח האחסון הפנימי של מצביע. 441 00:35:48,100 --> 00:35:55,940 אז המצביע שנמצא במחסנית, בלוק malloced הוא בערימה. 442 00:35:55,940 --> 00:36:01,240 הרבה אנשים מתבלבלים ואומרים int * x = malloc, x הוא בערימה. 443 00:36:01,240 --> 00:36:04,100 לא, מה x מצביע על הערימה. 444 00:36:04,100 --> 00:36:08,540 x עצמו בערימה, אלא אם מהסיבה כלשהי יש לך x להיות משתנה גלובלית, 445 00:36:08,540 --> 00:36:11,960 ובמקרה זה במקרה באזור אחר של זיכרון. 446 00:36:13,450 --> 00:36:20,820 אז שמירה על מסלול, דיאגרמות קופסה והחץ האלה הן די שכיחות לחידון. 447 00:36:20,820 --> 00:36:25,740 או אם זה לא בחידון 0, זה יהיה ביום 1 בחידון. 448 00:36:27,570 --> 00:36:31,940 אתה צריך לדעת את כל אלה, את השלבים בהידור 449 00:36:31,940 --> 00:36:35,740 מאז שיש לך לענות על שאלות באלה. כן. 450 00:36:35,740 --> 00:36:38,940 [תלמיד] נוכל ללכת על הצעדים האלה - >> בטח. 451 00:36:48,340 --> 00:36:58,640 לפני מדרגות והידור יש לנו preprocessing, 452 00:36:58,640 --> 00:37:16,750 איסוף, הרכבה, וקישור. 453 00:37:16,750 --> 00:37:21,480 Preprocessing. מה זה עושה? 454 00:37:29,720 --> 00:37:32,290 זה צעד הקל ביותר ב-- טוב, לא כמו - 455 00:37:32,290 --> 00:37:35,770 זה לא אומר שזה צריך להיות מובן מאליו, אבל זה צעד הקל ביותר. 456 00:37:35,770 --> 00:37:38,410 אתם יכולים ליישם את זה בעצמכם. כן. 457 00:37:38,410 --> 00:37:43,410 [תלמיד] קח את מה שיש לך כולל בכך והיא מעתיקה ולאחר מכן גם מגדירה. 458 00:37:43,410 --> 00:37:49,250 זה נראה לדברים כמו # # כולל ולהגדיר, 459 00:37:49,250 --> 00:37:53,800 וזה רק עותקים ומשחות מה אלו בעצם אומרים. 460 00:37:53,800 --> 00:37:59,240 אז כשאתה אומר # כולל cs50.h, בעיבוד המוקדם הוא העתקה והדבקת cs50.h 461 00:37:59,240 --> 00:38:01,030 אל קו זה. 462 00:38:01,030 --> 00:38:06,640 כשאתה אומר # להגדיר x להיות 4, בעיבוד המוקדם עובר את התכנית כולה 463 00:38:06,640 --> 00:38:10,400 ומחליף את כל המופעים של x עם 4. 464 00:38:10,400 --> 00:38:17,530 אז preprocessor לוקח קובץ C תקף ופלטי קובץ C תקף 465 00:38:17,530 --> 00:38:20,300 שבו הדברים היו להעתיק ולהדביק. 466 00:38:20,300 --> 00:38:24,230 אז עכשיו קומפילציה. מה זה עושה? 467 00:38:25,940 --> 00:38:28,210 [תלמיד] זה הולך מג' לינארי. 468 00:38:28,210 --> 00:38:30,970 >> [אודן] זה לא הולך כל הדרך לינארי. 469 00:38:30,970 --> 00:38:34,220 [תלמיד] לקוד מכונה אז? >> זה לא קוד מכונה. 470 00:38:34,220 --> 00:38:35,700 [תלמיד] עצרת? >> אסיפה. 471 00:38:35,700 --> 00:38:38,890 זה הולך לאסיפה לפני שהוא הולך כל הדרך לקוד C, 472 00:38:38,890 --> 00:38:45,010 ובמרבית השפות לעשות משהו כזה. 473 00:38:47,740 --> 00:38:50,590 פיק כל שפה ברמה גבוהה, ואם אתה הולך להדר אותו, 474 00:38:50,590 --> 00:38:52,390 סביר להניח להדר בצעדים. 475 00:38:52,390 --> 00:38:58,140 ראשון זה הולך לקמפל פייטון לC, אז זה הולך לקמפל C לעצרת, 476 00:38:58,140 --> 00:39:01,600 ולאחר מכן עצרת הולכת מתורגמת לינארי. 477 00:39:01,600 --> 00:39:07,800 אז הקומפילציה הולכת להביא אותו מג' לעצרת. 478 00:39:07,800 --> 00:39:12,130 מילת הידור פירושו בדרך כלל מביאה אותו מרמה גבוהה יותר 479 00:39:12,130 --> 00:39:14,340 לשפת תכנות ברמה נמוכה יותר. 480 00:39:14,340 --> 00:39:19,190 אז זה הצעד היחיד באוסף שבו אתה מתחיל עם שפה ברמה גבוהה 481 00:39:19,190 --> 00:39:23,270 וסופו של דבר בשפה ברמה נמוכה, ולכן הצעד נקרא הידור. 482 00:39:25,280 --> 00:39:33,370 [תלמיד] במהלך הקומפילציה, יניח שעשית # include cs50.h. 483 00:39:33,370 --> 00:39:42,190 האם מהדר קומפילצית cs50.h, כמו הפונקציות הניתנות לשם, 484 00:39:42,190 --> 00:39:45,280 ולתרגם את זה לקוד של עצרת, כמו גם, 485 00:39:45,280 --> 00:39:50,830 או שזה יהיה להעתיק ולהדביק משהו שהיה לפני העצרת? 486 00:39:50,830 --> 00:39:56,910 cs50.h יהיה די לא בסופו באסיפה. 487 00:39:59,740 --> 00:40:03,680 דברים כמו אבות טיפוס לפונקציות ודברים הם רק בשביל שתהיו זהיר. 488 00:40:03,680 --> 00:40:09,270 היא מבטיחה שהמהדר יכול לבדוק דברים כמו שאתה קורא פונקציות 489 00:40:09,270 --> 00:40:12,910 עם סוגי ההחזרה הנכונים ואת הטיעונים ודברים הנכונים. 490 00:40:12,910 --> 00:40:18,350 >> אז cs50.h יהיה מעובד לקובץ, ולאחר מכן כאשר זה הידור 491 00:40:18,350 --> 00:40:22,310 זה בעצם זרק אותו אחרי זה מוודא כי הכל הוא להיקרא בצורה נכונה. 492 00:40:22,310 --> 00:40:29,410 אבל את הפונקציות שהוגדרו בCS50 הספרייה, שהם נפרדים מcs50.h, 493 00:40:29,410 --> 00:40:33,610 אלה לא נערכו בנפרד. 494 00:40:33,610 --> 00:40:37,270 כי בעצם ירד בשלב הקישור, כדי שנגיע לזה בשנייה. 495 00:40:37,270 --> 00:40:40,100 אבל קודם, מה הרכבה? 496 00:40:41,850 --> 00:40:44,500 [תלמיד] עצרת לינארי? >> כן. 497 00:40:46,300 --> 00:40:48,190 הרכבה. 498 00:40:48,190 --> 00:40:54,710 אנחנו לא קוראים לזה הידור כי עצרת היא די תרגום טהור בינארי. 499 00:40:54,710 --> 00:41:00,230 יש היגיון במעט מאוד הולך מעצרת לינארי. 500 00:41:00,230 --> 00:41:03,180 זה בדיוק כמו להסתכל בטבלה, הו, יש לנו הוראה זו; 501 00:41:03,180 --> 00:41:06,290 מתאים לינארי 01110. 502 00:41:10,200 --> 00:41:15,230 וכן את הקבצים שהרכבה כלל תפוקות. קבצי o. 503 00:41:15,230 --> 00:41:19,020 ו. קבצי o הם מה שאנחנו אומרים זה לפני, 504 00:41:19,020 --> 00:41:21,570 איך קובץ לא צריך להיות פונקציה עיקרית. 505 00:41:21,570 --> 00:41:27,640 כל קובץ יכול להיות הידור עד. קובץ o כל עוד זה קובץ C תקף. 506 00:41:27,640 --> 00:41:30,300 זה יכול להיות הידור עד. O. 507 00:41:30,300 --> 00:41:43,030 עכשיו, הקישור הוא מה שבעצם מביא חבורה של. קבצי o ומביא אותם לביצוע. 508 00:41:43,030 --> 00:41:51,110 אז מה עושה מקשר הוא שאתה יכול לחשוב ספריית CS50 כ. קובץ O. 509 00:41:51,110 --> 00:41:56,980 זה קובץ בינארי שכבר נאסף. 510 00:41:56,980 --> 00:42:03,530 ולכן כאשר אתה לקמפל את הקובץ, hello.c, שקורא GetString, 511 00:42:03,530 --> 00:42:06,360 hello.c מקבל הידור עד hello.o, 512 00:42:06,360 --> 00:42:08,910 hello.o הוא עכשיו בינארי. 513 00:42:08,910 --> 00:42:12,830 היא משתמשת GetString, כך שהוא צריך ללכת אל cs50.o, 514 00:42:12,830 --> 00:42:16,390 והמקשר smooshes יחד ומעתיק GetString לקובץ זה 515 00:42:16,390 --> 00:42:20,640 ויוצא עם הרצה שיש את כל הפונקציות שהוא צריך. 516 00:42:20,640 --> 00:42:32,620 אז cs50.o הוא לא באמת קובץ פלט, אבל זה מספיק קרוב, שאין הבדל מהותי. 517 00:42:32,620 --> 00:42:36,880 כך שחיבור פשוט מביא את החבורה של קבצים יחד 518 00:42:36,880 --> 00:42:41,390 כך בנפרד מכילים את כל הפונקציות שאני צריך להשתמש 519 00:42:41,390 --> 00:42:46,120 ויוצר להרצה שתהיה ממש לרוץ. 520 00:42:48,420 --> 00:42:50,780 >> וכך זה גם מה שאנחנו אומרים זה לפני 521 00:42:50,780 --> 00:42:55,970 שם אתה יכול לקבל 1000. קבצי C, אתה לרכז את כולם ל. קבצי o, 522 00:42:55,970 --> 00:43:00,040 כנראה שייקח קצת זמן, ואז אתה משנה 1. קובץ c. 523 00:43:00,040 --> 00:43:05,480 אתה רק צריך להדר מחדש ש1. קובץ c ואז הכל לקשר מחדש אחר, 524 00:43:05,480 --> 00:43:07,690 לקשר את הכל בחזרה ביחד. 525 00:43:09,580 --> 00:43:11,430 [תלמיד] כשאתה מקשר אנו כותבים lcs50? 526 00:43:11,430 --> 00:43:20,510 כן, מה שlcs50. כי אותות הדגל למקשר כי אתה צריך להיות קישור שבספרייה. 527 00:43:26,680 --> 00:43:28,910 שאלות? 528 00:43:41,310 --> 00:43:46,860 האם עבר על ינארי האחר מ 5 שניות כי בהרצאה הראשונה? 529 00:43:50,130 --> 00:43:53,010 לא נראה לי. 530 00:43:55,530 --> 00:43:58,820 אתה צריך לדעת את כל הגדול אוס שאנחנו מתרחקים יותר, 531 00:43:58,820 --> 00:44:02,670 ואתה צריך להיות מסוגל, אם נתתי לך פונקציה, 532 00:44:02,670 --> 00:44:09,410 אתה אמור להיות מסוגל לומר שזה גדול O, בערך. או גם, הגדול O הוא מחוספס. 533 00:44:09,410 --> 00:44:15,300 אז אם אתה רואה לקנן לולאות הופנה על אותו המספר של דברים, 534 00:44:15,300 --> 00:44:22,260 כמו int i, i > [התלמיד] n בריבוע. >> זה נוטה להיות n בריבוע. 535 00:44:22,260 --> 00:44:25,280 אם מקונן משולש, הוא נוטה להיות n חתוך לקוביות. 536 00:44:25,280 --> 00:44:29,330 אז זה סוג של דבר שאתה צריך להיות מסוגל להצביע באופן מיידי. 537 00:44:29,330 --> 00:44:33,890 אתה צריך לדעת את סוג כניסה ומיון בועות ולמזג מיון וכל אלה. 538 00:44:33,890 --> 00:44:41,420 זה קל יותר להבין מדוע הם אלה n בריבוע וn log n וכל זה 539 00:44:41,420 --> 00:44:47,810 משום שאני חושב שהייתה בחידון שנה שבו אנחנו בעצם נתנו לך 540 00:44:47,810 --> 00:44:55,050 יישום של מיון בועות ואמר, "מהו זמן הריצה של פונקציה זו?" 541 00:44:55,050 --> 00:45:01,020 אז אם אתה מזהה את זה כסוג של בועה, אז אתה יכול להגיד n בריבוע באופן מיידי. 542 00:45:01,020 --> 00:45:05,470 אבל אם אתה רק מסתכל על זה, אתה אפילו לא צריך להבין מיון בועות זה; 543 00:45:05,470 --> 00:45:08,990 אתה יכול רק להגיד שזה עושה את זה ואת זה. זה n בריבוע. 544 00:45:12,350 --> 00:45:14,710 [תלמיד] האם יש דוגמאות קשות אתה יכול לבוא עם, 545 00:45:14,710 --> 00:45:20,370 כמו רעיון דומה של להבין? 546 00:45:20,370 --> 00:45:24,450 >> אני לא חושב שהייתי נותן לך את כל דוגמאות קשות. 547 00:45:24,450 --> 00:45:30,180 דבר מיון הבועות הוא כ קשוח כמונו הייתי הולכים, 548 00:45:30,180 --> 00:45:36,280 וגם זה, כל עוד אתה מבין שאתה iterating על המערך 549 00:45:36,280 --> 00:45:41,670 לכל רכיב במערך, שהולך להיות משהו שn בריבוע. 550 00:45:45,370 --> 00:45:49,940 יש שאלות כלליות, כמו זכות שיש לנו כאן - הו. 551 00:45:55,290 --> 00:45:58,530 רק לפני כמה ימים, דאג טען, "המצאתי אלגוריתם שיכול למיין מערך 552 00:45:58,530 --> 00:46:01,780 "מספרים של n בO (logn) זמן!" 553 00:46:01,780 --> 00:46:04,900 אז איך אנחנו יודעים שזה בלתי אפשרי? 554 00:46:04,900 --> 00:46:08,850 [תגובת תלמיד לא נשמעה] >> כן. 555 00:46:08,850 --> 00:46:13,710 לכל הפחות, יש לך לגעת בכל אחד מרכיבים במערך, 556 00:46:13,710 --> 00:46:16,210 אז אי אפשר למיין מערך של - 557 00:46:16,210 --> 00:46:20,850 אם הכל כדי לא ממוין, ואז אתה הולך להיות נוגע בכל דבר במערך, 558 00:46:20,850 --> 00:46:25,320 כך שזה בלתי אפשרי לעשות את זה בפחות מ O של n. 559 00:46:27,430 --> 00:46:30,340 [תלמיד] אתה הראית לנו דוגמה של להיות מסוגל לעשות את זה ב O של n 560 00:46:30,340 --> 00:46:33,920 אם אתה משתמש הרבה בזיכרון. >> כן. 561 00:46:33,920 --> 00:46:37,970 וזהו זה - אני לא זוכר מה כלומר - האם זה מיון מנייה? 562 00:46:47,360 --> 00:46:51,330 הממ. זה אלגוריתם מיון של מספרים שלם. 563 00:46:59,850 --> 00:47:05,100 אני מחפש את השם המיוחד לזה שאני לא זוכר בשבוע שעבר. 564 00:47:05,100 --> 00:47:13,000 כן. אלה הם סוגים של מינים שיכולים להשיג דברים הגדולים בO של n. 565 00:47:13,000 --> 00:47:18,430 אבל יש מגבלות, כמו שאתה יכול להשתמש במספרים שלמים רק עד מספר מסוים. 566 00:47:20,870 --> 00:47:24,560 בנוסף, אם אתה מנסה למיין זהו זה משהו - 567 00:47:24,560 --> 00:47:30,750 אם המערך שלך הוא 012, -12, 151, 4 מ' 568 00:47:30,750 --> 00:47:35,120 אז שאלמנט אחד הוא הולך להרוס את כל המיון לחלוטין. 569 00:47:42,060 --> 00:47:44,030 >> שאלות? 570 00:47:49,480 --> 00:47:58,870 [תלמיד] אם יש לך פונקציה רקורסיבית וזה רק גורם קריאות רקורסיביות 571 00:47:58,870 --> 00:48:02,230 בתוך הצהרת תמורה, זה זנב רקורסיבית, 572 00:48:02,230 --> 00:48:07,360 וכך הייתי שלא להשתמש יותר זיכרון במהלך הריצה 573 00:48:07,360 --> 00:48:12,550 או שזה יהיה לפחות להשתמש בזיכרון כלהשוות איטרטיבי פתרון? 574 00:48:12,550 --> 00:48:14,530 [אודן] כן. 575 00:48:14,530 --> 00:48:19,840 סביר להניח שמצב יהיה קצת איטי, אבל לא ממש. 576 00:48:19,840 --> 00:48:23,290 זנב רקורסיבית הוא די טוב. 577 00:48:23,290 --> 00:48:32,640 במבט חוזר במסגרות ערימה, יניח שיש לנו עיקרי 578 00:48:32,640 --> 00:48:42,920 ויש לנו שורת int (int x) או משהו. 579 00:48:42,920 --> 00:48:52,310 זו אינה פונקציה רקורסיבית מושלמת, אבל בר תשואה (x - 1). 580 00:48:52,310 --> 00:48:57,620 אז ברור, זה פגום. אתה צריך מקרי בסיס וכאלה. 581 00:48:57,620 --> 00:49:00,360 אבל הרעיון כאן הוא שמדובר בזנב רקורסיבית, 582 00:49:00,360 --> 00:49:06,020 כלומר, כאשר שורת שיחות עיקרית שזה הולך להגיע מסגרת המחסנית שלו. 583 00:49:09,550 --> 00:49:12,440 במסגרת זו יש ערימה הולכת להיות גוש קטן של זיכרון 584 00:49:12,440 --> 00:49:17,490 מתאים לx הטיעון שלו. 585 00:49:17,490 --> 00:49:25,840 וכך תניחו עיקרי קורה להתקשר בר (100); 586 00:49:25,840 --> 00:49:30,050 אז x הולך מתחיל כ100. 587 00:49:30,050 --> 00:49:35,660 אם המהדר מכיר בכך שזה פונקציה רקורסיבית זנב, 588 00:49:35,660 --> 00:49:38,540 אז כאשר הבר עושה השיחה רקורסיבית לבר, 589 00:49:38,540 --> 00:49:45,490 במקום לגרום מסגרת מחסנית חדשה, שבו הערימה מתחילה גדלה במידה רבה, 590 00:49:45,490 --> 00:49:48,220 סופו של דבר זה יפעל לערימה ואז אתה מקבל segfaults 591 00:49:48,220 --> 00:49:51,590 משום שזיכרון מתחיל התנגשות. 592 00:49:51,590 --> 00:49:54,830 >> אז במקום לגרום מסגרת מחסנית משלו, הוא יכול להבין, 593 00:49:54,830 --> 00:49:59,080 היי, אני לא באמת צריך לחזור למסגרת חבילה זו, 594 00:49:59,080 --> 00:50:08,040 אז במקום זה פשוט יחליף את הטיעון הזה עם 99 ולאחר מכן להתחיל בכל בר. 595 00:50:08,040 --> 00:50:11,810 ואז הוא יעשה את זה שוב והיא תגיע בר תשואה (x - 1), 596 00:50:11,810 --> 00:50:17,320 ובמקום לגרום מסגרת מחסנית חדשה, זה יהיה פשוט להחליף את הטיעון הנוכחי שלה עם 98 597 00:50:17,320 --> 00:50:20,740 ואז לקפוץ חזרה להתחלה של בר. 598 00:50:23,860 --> 00:50:30,430 אלה פעולות, מחליף את ערך 1 בערימה וקפצתי חזרה להתחלה, 599 00:50:30,430 --> 00:50:32,430 הם די יעילים. 600 00:50:32,430 --> 00:50:41,500 אז לא רק הוא זה אותו השימוש בזיכרון כפונקציה נפרדת האיטרטיבי 601 00:50:41,500 --> 00:50:45,390 כי אתה רק באמצעות מסגרת מחסנית 1, אבל אתה לא סובל חסרונות 602 00:50:45,390 --> 00:50:47,240 שיש לקרוא לפונקציות. 603 00:50:47,240 --> 00:50:50,240 פונקציות חיוג יכולות להיות קצת יקרות, כי יש לעשות את כל התקנה זו 604 00:50:50,240 --> 00:50:52,470 ופירוק וכל הדברים האלה. 605 00:50:52,470 --> 00:50:58,160 אז רקורסיה זנב זה טוב. 606 00:50:58,160 --> 00:51:01,170 [תלמיד] מדוע לא ליצור שלבים חדשים? 607 00:51:01,170 --> 00:51:02,980 כי הוא מבין שזה לא צריך. 608 00:51:02,980 --> 00:51:07,800 הקריאה לסרגל פשוט חוזרת שיחה רקורסיבית. 609 00:51:07,800 --> 00:51:12,220 אז הוא לא צריך לעשות שום דבר עם ערך ההחזרה. 610 00:51:12,220 --> 00:51:15,120 זה רק הולך להחזיר אותו באופן מיידי. 611 00:51:15,120 --> 00:51:20,530 אז זה רק הולך להחליף את הטיעון שלו ולהתחיל מחדש. 612 00:51:20,530 --> 00:51:25,780 וגם, אם אין לך את הגרסה רקורסיבית הזנב, 613 00:51:25,780 --> 00:51:31,460 ואז אתה מקבל את כל הברים האלה בי כאשר סרגל זה מחזיר 614 00:51:31,460 --> 00:51:36,010 יש להחזיר את הערך שלו לזה, ואז שהבר מייד חוזר 615 00:51:36,010 --> 00:51:39,620 וזה מחזיר את הערך שלו לזה, אז זה רק הולך לחזור מייד 616 00:51:39,620 --> 00:51:41,350 ולהחזיר את הערך שלו לזה. 617 00:51:41,350 --> 00:51:45,350 אז אתה שומר את זה צץ כל הדברים האלה מעל הערימה 618 00:51:45,350 --> 00:51:48,730 מאז ערך ההחזרה הוא פשוט הולך לעבור את כל הדרך חזרה למעלה בכל מקרה. 619 00:51:48,730 --> 00:51:55,400 אז למה לא פשוט להחליף את הטיעון שלנו בטענה מתעדכנת ולהתחיל מחדש? 620 00:51:57,460 --> 00:52:01,150 אם הפונקציה אינה רקורסיבית זנב, אם אתה עושה משהו כמו - 621 00:52:01,150 --> 00:52:07,530 [תלמיד] אם בר (x + 1). >> כן. 622 00:52:07,530 --> 00:52:11,770 >> אז אם אתה שם אותו במצב, ואז אתה עושה משהו עם ערך ההחזרה. 623 00:52:11,770 --> 00:52:16,260 או אפילו אם אתה פשוט עושה את התשואה 2 * הבר (x - 1). 624 00:52:16,260 --> 00:52:23,560 אז עכשיו בר (x - 1) צריך לחזור על מנת שזה כדי לחשב 2 פעמים שערך, 625 00:52:23,560 --> 00:52:26,140 אז עכשיו זה צריך מסגרת ערימה הנפרדת משלו, 626 00:52:26,140 --> 00:52:31,180 ועכשיו, לא משנה כמה קשה אתה מנסה, אתה הולך צריך - 627 00:52:31,180 --> 00:52:34,410 זה לא זנב רקורסיבית. 628 00:52:34,410 --> 00:52:37,590 [תלמיד] האם אני מנסה להביא רקורסיה לשאוף לרקורסיה זנב - 629 00:52:37,590 --> 00:52:41,450 [אודן] בעולם אידיאלי, אבל בCS50 אתה לא צריך. 630 00:52:43,780 --> 00:52:49,280 על מנת לקבל רקורסיה זנב, בדרך כלל, אתה מגדיר את טיעון נוסף 631 00:52:49,280 --> 00:52:53,550 שם בר ייקח x int לתוך y 632 00:52:53,550 --> 00:52:56,990 ו-y מתאים לדבר האולטימטיבי שאתה רוצה לחזור. 633 00:52:56,990 --> 00:53:03,650 אז זה שאתה הולך תחזור בר (x - 1), 2 * y. 634 00:53:03,650 --> 00:53:09,810 אז זה רק ברמה גבוהה איך להפוך את הדברים להיות זנב רקורסיבית. 635 00:53:09,810 --> 00:53:13,790 אבל טיעון הנוסף - 636 00:53:13,790 --> 00:53:17,410 ואז בסופו של דבר כאשר אתה מגיע למקרה הבסיס שלך, אתה פשוט לחזור y 637 00:53:17,410 --> 00:53:22,740 מכיוון שאספת כל הזמן את ערך ההחזרה רצויה. 638 00:53:22,740 --> 00:53:27,280 אתה סוג של עושה את זה כבר אבל ערוך את השימוש בשיחות רקורסיבית. 639 00:53:32,510 --> 00:53:34,900 שאלות? 640 00:53:34,900 --> 00:53:39,890 [תלמיד] אולי על חשבון מצביע, כמו בעת שימוש בחוטים. >> בטח. 641 00:53:39,890 --> 00:53:43,610 פעולות אריתמטיות על מצביעים. 642 00:53:43,610 --> 00:53:48,440 בעת שימוש במחרוזות זה קל משום שמייתרים הם כוכבי char, 643 00:53:48,440 --> 00:53:51,860 תווים הם לנצח ותמיד בית אחד, 644 00:53:51,860 --> 00:53:57,540 וכן פעולות אריתמטיות על המצביעים הן שווות ערך לחשבון רגיל כאשר אתה מתעסק עם חוטים. 645 00:53:57,540 --> 00:54:08,790 בואו רק נאמר char * s = "שלום". 646 00:54:08,790 --> 00:54:11,430 אז יש לנו בלוק בזיכרון. 647 00:54:19,490 --> 00:54:22,380 זה צריך 6 בתים כי אתה תמיד צריך null terminator. 648 00:54:22,380 --> 00:54:28,620 וchar * s עומדת להצביע על תחילתו של מערך זה. 649 00:54:28,620 --> 00:54:32,830 אז זה מצביע לשם. 650 00:54:32,830 --> 00:54:36,710 עכשיו, זה בעצם איך כל מערך עובד, 651 00:54:36,710 --> 00:54:40,780 ללא קשר לשאלה אם זה היה החזר על ידי malloc או בין אם זה בערימה. 652 00:54:40,780 --> 00:54:47,110 כל מערך הוא בעצם מצביע לתחילת המערך, 653 00:54:47,110 --> 00:54:53,640 ואז כל פעולת מערך, כל אינדקס, הוא פשוט נכנס לאותו מערך מסוים קיזוז. 654 00:54:53,640 --> 00:55:05,360 >> לכן, כאשר אני אומר משהו כמו זה [3]; זה הולך וספירה של 3 תווים פנימה 655 00:55:05,360 --> 00:55:12,490 אז זה [3], יש לנו 0, 1, 2, 3, כך שנ [3] הולך להתייחס לזה אני. 656 00:55:12,490 --> 00:55:20,460 [תלמיד] ואנחנו יכולים להגיע לאותו ערך על ידי ביצוע של + 3 ולאחר מכן כוכב סוגריים? 657 00:55:20,460 --> 00:55:22,570 כן. 658 00:55:22,570 --> 00:55:26,010 זה שווה * (s + 3); 659 00:55:26,010 --> 00:55:31,240 וזה לנצח, ותמיד שווה לא משנה מה אתה עושה. 660 00:55:31,240 --> 00:55:34,070 אתה לא צריך להשתמש בתחביר הסוגר. 661 00:55:34,070 --> 00:55:37,770 אתה תמיד יכול להשתמש ב* (s + 3) תחביר. 662 00:55:37,770 --> 00:55:40,180 אנשים שנוטים לאהוב את תחביר הסוגר. 663 00:55:40,180 --> 00:55:43,860 [תלמיד] אז כל המערכים הם למעשה רק מצביעים. 664 00:55:43,860 --> 00:55:53,630 קיימת הבחנה קלה כשאני אומר int x [4]; >> [תלמיד] שהאם ליצור את הזיכרון? 665 00:55:53,630 --> 00:56:03,320 [אודן] זה הולך ליצור 4 ints במחסנית, ולכן 16 בתים באופן כללי. 666 00:56:03,320 --> 00:56:05,700 זה הולך ליצור 16 בתים על הערימה. 667 00:56:05,700 --> 00:56:09,190 x אינו מאוחסן בכל מקום. 668 00:56:09,190 --> 00:56:13,420 זה רק סמל מתייחס לתחילתו של העניין. 669 00:56:13,420 --> 00:56:17,680 מכיוון שאתה הצהרת המערך פנימי של פונקציה זו, 670 00:56:17,680 --> 00:56:22,340 מה המהדר הוא הולך לעשות הוא פשוט להחליף את כל המופעים של x משתנה 671 00:56:22,340 --> 00:56:26,400 עם בו זה קרה לבחור לשים 16 בתים אלה. 672 00:56:26,400 --> 00:56:30,040 זה לא יכול לעשות את זה עם char * בגלל זה הוא מצביע בפועל. 673 00:56:30,040 --> 00:56:32,380 זה בחינם ואז להצביע על דברים אחרים. 674 00:56:32,380 --> 00:56:36,140 x הוא קבוע. אתה לא יכול לקבל אותו צבע על מערך שונה. >> [תלמיד] אוקיי. 675 00:56:36,140 --> 00:56:43,420 אבל הרעיון הזה, אינדקס זה, הוא זהה, ללא קשר לשאלה אם זה מערך מסורתי 676 00:56:43,420 --> 00:56:48,230 או אם זה מצביע על משהו או אם זה מצביע למערך malloced. 677 00:56:48,230 --> 00:56:59,770 ולמעשה, זה כל כך שווה שזה גם את אותו הדבר. 678 00:56:59,770 --> 00:57:05,440 זה בעצם רק מתרגם מה בתוך הסוגריים ומה שנשארו מאת הסוגריים, 679 00:57:05,440 --> 00:57:07,970 מוסיף אותם יחד, וdereferences. 680 00:57:07,970 --> 00:57:14,710 כך שזה רק תקף כ* (s + 3) או של [3]. 681 00:57:16,210 --> 00:57:22,090 [תלמיד] האם יש לך עצות המצביעות על מערכים 2-ממדיים? 682 00:57:22,090 --> 00:57:27,380 >> זה קשה יותר. באופן מסורתי, לא. 683 00:57:27,380 --> 00:57:34,720 מערך 2-ממדי הוא פשוט מערך 1-ממדי עם חלק תחביר נוח 684 00:57:34,720 --> 00:57:54,110 כי כשאני אומר int x [3] [3], זה באמת רק מערך 1 עם 9 ערכים. 685 00:57:55,500 --> 00:58:03,000 ולכן, כשהמדד, המהדר יודע למה אני מתכוון. 686 00:58:03,000 --> 00:58:13,090 אם אני אומר x [1] [2], הוא יודע שאני רוצה ללכת לשורה השנייה, אז זה הולך לדלג על 3 הראשונים, 687 00:58:13,090 --> 00:58:17,460 ואז הוא רוצה את הדבר השני בזה, אז זה הולך לקבל את זה. 688 00:58:17,460 --> 00:58:20,480 אבל זה עדיין רק במערך בודד ממדי. 689 00:58:20,480 --> 00:58:23,660 ואז אם אני רוצה להקצות למצביע שהמערך, 690 00:58:23,660 --> 00:58:29,770 הייתי אומר int * p = x; 691 00:58:29,770 --> 00:58:33,220 הסוג של x הוא פשוט - 692 00:58:33,220 --> 00:58:38,280 זה סוג אמירה גס של x שכן הוא רק סמל וזה לא משתנה בפועל, 693 00:58:38,280 --> 00:58:40,140 אבל זה רק * int. 694 00:58:40,140 --> 00:58:44,840 x הוא פשוט מצביע להתחלה של זה. >> [תלמיד] אוקיי. 695 00:58:44,840 --> 00:58:52,560 ואז אני לא יוכל לגשת [1] [2]. 696 00:58:52,560 --> 00:58:58,370 אני חושב שיש תחביר מיוחד להכרזה על מצביע, 697 00:58:58,370 --> 00:59:12,480 משהו מגוחך כמו int (* p [-. משהו מגוחך לחלוטין אני אפילו לא יודע. 698 00:59:12,480 --> 00:59:17,090 אבל יש תחביר להכרזת מצביעים כמו עם סוגריים וכל מיני דברים. 699 00:59:17,090 --> 00:59:22,960 זה אפילו לא יכול לתת לך לעשות את זה. 700 00:59:22,960 --> 00:59:26,640 אני יכול להביט אחורה על משהו שהיה אומר לי את האמת. 701 00:59:26,640 --> 00:59:34,160 אני אסתכל על זה מאוחר יותר, אם יש תחביר לנקודה. אבל אתה אף פעם לא תראה אותו. 702 00:59:34,160 --> 00:59:39,670 ואפילו התחביר הוא כל כך ארכאי, שאם אתה משתמש בו, אנשים יהיו מבולבלים. 703 00:59:39,670 --> 00:59:43,540 מערכים רבים ממדים הם די נדירים כפי שהוא. 704 00:59:43,540 --> 00:59:44,630 אתה פחות או יותר - 705 00:59:44,630 --> 00:59:48,490 ובכן, אם אתה עושה דברי מטריצה ​​זה לא הולך להיות נדיר, 706 00:59:48,490 --> 00:59:56,730 אבל ב-C אתה רק לעתים נדירות הולך להיות באמצעות מערכים רבים ממדים. 707 00:59:57,630 --> 01:00:00,470 כן. >> [תלמיד] בואו נגיד שיש לך באמת זמן מערך. 708 01:00:00,470 --> 01:00:03,900 >> אז בזיכרון וירטואלי זה להיראות כל ברציפות, 709 01:00:03,900 --> 01:00:05,640 כמו האלמנטים זכות זו לצד זו, 710 01:00:05,640 --> 01:00:08,770 אבל בזיכרון הפיזי, זה יהיה אפשרי עבור שיש לפצל את? >> כן. 711 01:00:08,770 --> 01:00:16,860 איך עובד זיכרון וירטואלי שזה רק מפריד - 712 01:00:19,220 --> 01:00:24,860 יחידת ההקצאה היא דף, שנוטה להיות 4 ק"ג, 713 01:00:24,860 --> 01:00:29,680 ולכן כאשר תהליך אומר, היי, אני רוצה להשתמש בזיכרון הזה, 714 01:00:29,680 --> 01:00:35,970 מערכת ההפעלה הולכת להקצות אותו 4 ק"ג שלגוש הקטן של זיכרון. 715 01:00:35,970 --> 01:00:39,100 גם אם אתה משתמש בייט אחד קטן בכל הבלוק של זיכרון, רק 716 01:00:39,100 --> 01:00:42,850 מערכת ההפעלה הוא הולך לתת לו את 4 ק"ג המלא. 717 01:00:42,850 --> 01:00:49,410 אז מה שזה אומר זה שיהיה לי - בואו נגיד שזה הערימה שלי. 718 01:00:49,410 --> 01:00:53,180 מערך זה יכול להיות מופרד. הערימה שלי יכלה להיות מגה ומגה. 719 01:00:53,180 --> 01:00:55,020 הערימה שלי יכולה להיות ענקית. 720 01:00:55,020 --> 01:01:00,220 אבל הערימה עצמו יש להיות מפוצל לדפים בודדים, 721 01:01:00,220 --> 01:01:09,010 שאם אנחנו מסתכלים על כאן בואו נגיד שזה הזיכרון RAM שלנו, 722 01:01:09,010 --> 01:01:16,600 אם יש לי 2 ג'יגה בייט של זכרון RAM, זה הוא 0 כתובת ממשית כמו בייט של זכרון RAM 0, 723 01:01:16,600 --> 01:01:22,210 וזה כאן 2 ג'יגה כל הדרך למטה. 724 01:01:22,210 --> 01:01:27,230 אז דף זה עשוי להתאים לבלוק הזה כאן. 725 01:01:27,230 --> 01:01:29,400 ייתכן שדף זה מתאים לבלוק הזה כאן. 726 01:01:29,400 --> 01:01:31,560 זה עשוי להתאים לזה כאן. 727 01:01:31,560 --> 01:01:35,540 אז מערכת ההפעלה היא חופשיה להקצות זיכרון פיזי 728 01:01:35,540 --> 01:01:39,320 לכל דף באתר באופן שרירותי. 729 01:01:39,320 --> 01:01:46,180 וזה אומר שאם גבול זה קורה כדי לרכב על מערך, 730 01:01:46,180 --> 01:01:50,070 מערך במקרה נותר מכל זה וזכותו של צו זה של דף, 731 01:01:50,070 --> 01:01:54,460 אז מערך שהוא הולך להיות מפוצל בזיכרון פיזי. 732 01:01:54,460 --> 01:01:59,280 ואז כשאתה יוצא מהתכנית, כאשר התהליך מסתיים, 733 01:01:59,280 --> 01:02:05,690 מיפויים אלו מקבלים נמחקו ואז זה חופשי לשימוש בלוקים קטנים האלה לדברים אחרים. 734 01:02:14,730 --> 01:02:17,410 עוד שאלות? 735 01:02:17,410 --> 01:02:19,960 [התלמיד] פעולות אריתמטיות על המצביעים. >> אה, כן. 736 01:02:19,960 --> 01:02:28,410 מייתרים היו יותר קלים, אבל מסתכלים על משהו כמו ints, 737 01:02:28,410 --> 01:02:35,000 כך חזרה לint x [4]; 738 01:02:35,000 --> 01:02:41,810 בין אם זה מערך או בין אם זה מצביע למערך malloced של 4 מספרים שלמים, 739 01:02:41,810 --> 01:02:47,060 זה הולך להיות מטופלים באותה הדרך. 740 01:02:50,590 --> 01:02:53,340 [תלמיד] אז מערכים הם בערימה? 741 01:03:01,400 --> 01:03:05,270 [אודן] מערכים לא נמצאים בערימה. >> [תלמיד] הו. 742 01:03:05,270 --> 01:03:08,320 >> [אודן] סוג זה של מערך נוטה להיות במחסנית 743 01:03:08,320 --> 01:03:12,220 אלא אם הכרזת עליו ב-- התעלמות משתנים גלובליים. אין להשתמש במשתנים גלובליים. 744 01:03:12,220 --> 01:03:16,280 בתוך פונקציה אני אומר int x [4]; 745 01:03:16,280 --> 01:03:22,520 זה הולך ליצור בלוק 4-מספר שלם במחסנית למערך זה. 746 01:03:22,520 --> 01:03:26,960 אבל זה malloc (4 * sizeof (int)); הולך ללכת על הערימה. 747 01:03:26,960 --> 01:03:31,870 אבל אחרי נקודה זו אני יכול להשתמש x ו-p בפחות או יותר את אותן דרכים, 748 01:03:31,870 --> 01:03:36,140 למעט החריגים שאמרתי קודם עליך יכול להקצות מחדש p. 749 01:03:36,140 --> 01:03:40,960 מבחינה טכנית, הגדלים שלהם שונים במקצת, אבל זה לחלוטין לא רלוונטי. 750 01:03:40,960 --> 01:03:43,310 לעולם לא תשתמש בם הגדלים. 751 01:03:48,020 --> 01:03:56,810 P אני יכול לומר p [3] = 2; או x [3] = 2; 752 01:03:56,810 --> 01:03:59,680 אתה יכול להשתמש בם בדיוק באותן הדרכים. 753 01:03:59,680 --> 01:04:01,570 אז פעולות אריתמטיות על מצביעים עכשיו - כן. 754 01:04:01,570 --> 01:04:07,390 [תלמיד] אתה לא צריך לעשות * p אם יש לך את הסוגריים? 755 01:04:07,390 --> 01:04:11,720 בסוגריים הם dereference סמוי. >> אוקיי. 756 01:04:11,720 --> 01:04:20,200 למעשה, גם מה שאתה אומר עם אתה יכול לקבל מערכים רבים ממדים 757 01:04:20,200 --> 01:05:02,650 עם מצביעים, מה שאתה יכול לעשות הוא משהו כמו, יניח, int ** PP = malloc (sizeof (int *) * 5); 758 01:05:02,650 --> 01:05:06,900 אני רק כותב את כל זה בתחילת המופע. 759 01:05:37,880 --> 01:05:41,020 אני לא רוצה את זה. 760 01:05:41,020 --> 01:05:42,550 אוקיי. 761 01:05:42,550 --> 01:05:48,910 מה שעשיתי כאן הוא - זה צריך להיות עמ '[i]. 762 01:05:48,910 --> 01:05:53,680 אז PP הוא מצביע למצביע. 763 01:05:53,680 --> 01:06:02,420 אתה mallocing עמ להצביע למערך של 5 כוכבי int. 764 01:06:02,420 --> 01:06:10,950 אז בזיכרון יש לך בעמ 'הערימה 765 01:06:10,950 --> 01:06:20,150 זה הולך להצביע למערך של 5 בלוקים שהם עצמם כל מצביעים. 766 01:06:20,150 --> 01:06:28,210 ואז כשmalloc כאן למטה, אני malloc שכל אחד מהמצביעים הבודדים האלה 767 01:06:28,210 --> 01:06:32,080 צריך להצביע על בלוק נפרד של 4 בתים בערמה. 768 01:06:32,080 --> 01:06:35,870 אז זה מצביע על 4 בתים. 769 01:06:37,940 --> 01:06:40,660 ואחת נקודות זה ל4 בתים שונים. 770 01:06:40,660 --> 01:06:43,200 >> וכולם מצביעים על 4 הבתים שלהם. 771 01:06:43,200 --> 01:06:49,080 זה נותן לי דרך לעשות דברים רבים ממדיים. 772 01:06:49,080 --> 01:06:58,030 אני יכול לומר pp [3] [4], אבל עכשיו זה לא אותו הדבר כמו מערכים רב ממדים 773 01:06:58,030 --> 01:07:05,390 בגלל מערכים רבים ממדיו תורגמו [3] [4] ליחיד לקזז לתוך מערך x. 774 01:07:05,390 --> 01:07:14,790 עמ dereferences זה, ניגש המדד השלישי, אז שdereferences 775 01:07:14,790 --> 01:07:20,790 וכניסות - 4 תהיינה חוקיות - המדד השני. 776 01:07:24,770 --> 01:07:31,430 לעומת זאת, כאשר היו לנו int x [3] [4] לפני כמערך רב ממדי 777 01:07:31,430 --> 01:07:35,740 וכאשר אתה לוחץ פעמי סוגר זה באמת רק dereference יחיד, 778 01:07:35,740 --> 01:07:40,490 אתה עוקב אחרי מצביע בודד ולאחר מכן לקזז, 779 01:07:40,490 --> 01:07:42,850 זה באמת הפניות 2D. 780 01:07:42,850 --> 01:07:45,840 אתה עוקב 2 מצביעים נפרדים. 781 01:07:45,840 --> 01:07:50,420 אז זה גם מבחינה טכנית מאפשר לך יש מערכים רבים ממדים 782 01:07:50,420 --> 01:07:53,550 שבו כל פרט הוא מערך גדלים שונים. 783 01:07:53,550 --> 01:07:58,000 אז אני חושב שמערכים רבים ממדים משוננים הוא מה זה נקרא 784 01:07:58,000 --> 01:08:01,870 מאז באמת הדבר הראשון שיכל להצביע על משהו שיש לו 10 אלמנטים, 785 01:08:01,870 --> 01:08:05,540 הדבר השני יכל להצביע על משהו שיש לו 100 אלמנטים. 786 01:08:05,540 --> 01:08:10,790 [תלמיד] האם יש הגבלה למספר המצביעים שאתה יכול לקבל 787 01:08:10,790 --> 01:08:14,290 הצבעה על מצביעים אחרים? מספר >> 788 01:08:14,290 --> 01:08:17,010 אתה יכול להיות int ***** p. 789 01:08:18,050 --> 01:08:23,760 חזרו לפעולות אריתמטיות על מצביעים - >> [תלמיד] הו. >> כן. 790 01:08:23,760 --> 01:08:35,649 [תלמיד] אם יש לי int *** p ואז אני עושה ביטול הפניה ואני אומר * p שווה לערך הזה, 791 01:08:35,649 --> 01:08:39,560 האם זה רק הולך לעשות רמת 1 של ביטול הפניה? >> כן. 792 01:08:39,560 --> 01:08:43,340 אז אם אני רוצה לגשת הדבר שהמצביע האחרון מצביע על - 793 01:08:43,340 --> 01:08:46,210 אז אתה עושה עמ '***. >> אוקיי. 794 01:08:46,210 --> 01:08:54,080 אז זה p מצביע לבלוק 1, מצביע על בלוק נוסף, מצביע על בלוק אחר. 795 01:08:54,080 --> 01:09:02,010 אז אם אתה עושה * p = משהו אחר, אז אתה משנה את זה 796 01:09:02,010 --> 01:09:13,640 עכשיו להצביע לגוש אחר. >> אוקיי. 797 01:09:13,640 --> 01:09:17,649 >> [אודן] ואם אלה malloced, אז יש לך עכשיו דלף זיכרון 798 01:09:17,649 --> 01:09:20,430 אלא אם קורה לך יש הפניות שונות של אלה 799 01:09:20,430 --> 01:09:25,270 מאחר שאתה לא יכול לחזור לאלה אלה שפשוט זרקו. 800 01:09:25,270 --> 01:09:29,550 פעולות אריתמטיות על מצביעים. 801 01:09:29,550 --> 01:09:36,310 הולך להקצות מערך של 4 מספרים שלמים, x [4] int 802 01:09:36,310 --> 01:09:40,670 כאשר x הולך להצביע על תחילתו של המערך. 803 01:09:40,670 --> 01:09:50,420 לכן, כאשר אני אומר משהו כמו x [1]; אני רוצה שזה אומר ללכת למספר השלם השני במערך, 804 01:09:50,420 --> 01:09:53,319 שיהיה זה אחד. 805 01:09:53,319 --> 01:10:04,190 אבל באמת, זה 4 בתים לתוך המערך השלם מאז זה לוקח עד 4 בתים. 806 01:10:04,190 --> 01:10:08,470 אז קיזוז של 1 באמת אומר קיזוז של 1 807 01:10:08,470 --> 01:10:12,030 פעמים את הגודל של כל הסוג של המערך הוא. 808 01:10:12,030 --> 01:10:17,170 זהו מערך של מספרים שלמים, ולכן הוא יודע לעשות 1 פעמי גודל של int מתי היא רוצה לקזז. 809 01:10:17,170 --> 01:10:25,260 תחביר האחר. זכור שזה שווה ערך ל * (x + 1); 810 01:10:25,260 --> 01:10:35,250 כשאני אומר מצביע + 1, מה שמחזיר הוא הכתובת שמצביע האחסון 811 01:10:35,250 --> 01:10:40,360 בתוספת 1 פעמים בגודל של הסוג של המצביע. 812 01:10:40,360 --> 01:10:59,510 אז אם x = ox100, אז x + 1 = ox104. 813 01:10:59,510 --> 01:11:19,750 ואתה יכול להשמיץ את זה ואומר משהו כמו char * c = (char *) x; 814 01:11:19,750 --> 01:11:23,050 ועכשיו ג הולך להיות באותה הכתובת כמו x. 815 01:11:23,050 --> 01:11:26,040 ג הולך להיות שווה לox100, 816 01:11:26,040 --> 01:11:31,490 אבל c + 1 הולך להיות שווה לox101 817 01:11:31,490 --> 01:11:38,030 מאז פעולות אריתמטיות על מצביעים תלוי בסוג של המצביע שאתה מוסיף ל. 818 01:11:38,030 --> 01:11:45,390 אז c + 1, זה נראה בג, זה מצביע char, אז זה הולך להוסיף 1 פעמי גודל של char, 819 01:11:45,390 --> 01:11:48,110 שתמיד הולך להיות 1, כך שאתה מקבל 101, 820 01:11:48,110 --> 01:11:54,890 ואילו אם אני עושה x, שגם הוא עדיין 100, x + 1 הולך להיות 104. 821 01:11:56,660 --> 01:12:06,340 [תלמיד] אתה יכול להשתמש C + + כדי לקדם את המצביע עד ליום 1? 822 01:12:06,340 --> 01:12:09,810 כן, אתה יכול. 823 01:12:09,810 --> 01:12:16,180 אתה לא יכול לעשות את זה עם x כי x הוא רק סמל, הוא קבוע, אתה לא יכול לשנות את x. 824 01:12:16,180 --> 01:12:22,610 >> אבל ג קורה רק כדי להיות מצביע, אז + + C הוא חוקי לחלוטין וזה יהיה להגדיל ב 1. 825 01:12:22,610 --> 01:12:32,440 אם ג היה פשוט * int, אז C + + יהיה 104. 826 01:12:32,440 --> 01:12:41,250 + + פעולות אריתמטיות על מצביעים עושה בדיוק כמו c + 1 יצטרך לעשות פעולות אריתמטיות על מצביעים. 827 01:12:43,000 --> 01:12:48,870 זו בעצם איך המון דברים כמו סוג המיזוג - 828 01:12:49,670 --> 01:12:55,710 במקום ליצור העתקים של דברים, אתה יכול במקום לעבור - 829 01:12:55,710 --> 01:13:02,400 כאילו שאם אני רוצה לעבור את המחצית זו של המערך - בוא נמחק חלק מזה. 830 01:13:04,770 --> 01:13:10,520 נניח שאני רוצה לעבור את הצד הזה של המערך לפונקציה. 831 01:13:10,520 --> 01:13:12,700 מה הייתי עובר לפונקציה? 832 01:13:12,700 --> 01:13:17,050 אם אני עובר x, אני מעביר את הכתובת הזאת. 833 01:13:17,050 --> 01:13:23,780 אבל אני רוצה להעביר את הכתובת המסוימת הזה. אז מה כדאי לי לעבור? 834 01:13:23,780 --> 01:13:26,590 [תלמיד] פוינטר + 2? 835 01:13:26,590 --> 01:13:29,350 [אודן] אז x + 2. כן. 836 01:13:29,350 --> 01:13:31,620 זה הולך להיות זו כתובת. 837 01:13:31,620 --> 01:13:42,810 גם אתה לעתים קרובות מאוד לראות את זה כx [2] ולאחר מכן את הכתובת שלו. 838 01:13:42,810 --> 01:13:47,850 אז אתה צריך לקחת את הכתובת שלו כי הסוגר הוא dereference סמוי. 839 01:13:47,850 --> 01:13:53,250 x [2] מתייחס לערך שהוא בתיבה זו, ואז אתה רוצה את הכתובת של תיבה, 840 01:13:53,250 --> 01:13:56,850 אז אתה אומר & x [2]. 841 01:13:56,850 --> 01:14:02,880 אז זה משהו איך בסוג המיזוג שבו אתה רוצה להעביר חצי מהרשימה למשהו 842 01:14:02,880 --> 01:14:08,790 אתה באמת רק לעבור & x [2], ועכשיו ככל השיחה רקורסיבית היא מודאגת, 843 01:14:08,790 --> 01:14:12,510 המערך החדש שלי מתחיל שם. 844 01:14:12,510 --> 01:14:15,130 שאלות הרגע אחרונות. 845 01:14:15,130 --> 01:14:20,050 [תלמיד] אם לא מכניס אמפרסנד או - מה שנקרא ש? >> כוכב? 846 01:14:20,050 --> 01:14:23,200 [תלמיד] כוכב. >> בחינה טכנית, מפעיל dereference, אבל - >> [תלמיד] Dereference. 847 01:14:23,200 --> 01:14:29,310 >> אם אנחנו לא לשים כוכב או אמפרסנד, מה קורה אם אני פשוט אומר y = x ו-x הוא מצביע? 848 01:14:29,310 --> 01:14:34,620 מה הוא הסוג של Y? >> [תלמיד] אני פשוט אגיד את המצביע זה 2. 849 01:14:34,620 --> 01:14:38,270 אז אם אתה רק אומר y = x, עכשיו x ו-y נקודה לאותו הדבר. >> [תלמיד] צבע על אותו הדבר. 850 01:14:38,270 --> 01:14:45,180 ואם x הוא מצביע int? >> זה הייתי מתלונן, כי אתה לא יכול להקצות מצביעים. 851 01:14:45,180 --> 01:14:46,540 [תלמיד] אוקיי. 852 01:14:46,540 --> 01:14:51,860 זכור כי מצביעים, למרות שאנחנו מציירים אותם כחצים, 853 01:14:51,860 --> 01:15:02,010 באמת כל מה שהם החנות - int * x - באמת כל x הוא האחסון היא משהו כמו ox100, 854 01:15:02,010 --> 01:15:06,490 שמקרה אנו מייצגים כמצביע לבלוק מאוחסן ב 100. 855 01:15:06,490 --> 01:15:19,660 לכן, כאשר אני אומר int * y = x; אני פשוט מעתיק ox100 לתוך y, 856 01:15:19,660 --> 01:15:24,630 שאנחנו רק הולכים לייצג כy, גם הוא מכוונים לox100. 857 01:15:24,630 --> 01:15:39,810 ואם אני אומר אני int = (int) x, ואז אני הולך לאחסון כל מה שהערך של ox100 הוא 858 01:15:39,810 --> 01:15:45,100 בתוכו, אבל עכשיו זה הולך להתפרש כשלם במקום מצביע. 859 01:15:45,100 --> 01:15:49,310 אבל אתה צריך גבס או אחר זה לא יתלונן. 860 01:15:49,310 --> 01:15:53,300 [תלמיד] אז אתה מתכוון להטיל - 861 01:15:53,300 --> 01:16:00,290 האם זה הולך להיות ליהוק int של int x או ליהוק של Y? 862 01:16:00,290 --> 01:16:03,700 [אודן] מה? 863 01:16:03,700 --> 01:16:07,690 [תלמיד] אוקיי. לאחר סוגריים אלה הולך להיות x או איים שם? 864 01:16:07,690 --> 01:16:11,500 >> [אודן] בכל מקרה. x ו-y הם שווים ערך. >> [תלמיד] אוקיי. 865 01:16:11,500 --> 01:16:14,390 בגלל שהם שני המצביעים. >> כן. 866 01:16:14,390 --> 01:16:21,050 [תלמיד] אז זה היית לאחסן 100 הקסדצימלי בצורה שלמה? >> [אודן] כן. 867 01:16:21,050 --> 01:16:23,620 אבל לא את הערך של מה שהוא מצביע. 868 01:16:23,620 --> 01:16:29,940 [אודן] כן. >> [תלמיד] אז רק את הכתובת בצורה שלמה. אוקיי. 869 01:16:29,940 --> 01:16:34,720 [אודן] אם אתה רוצה מסיבה מוזרה, 870 01:16:34,720 --> 01:16:38,900 אתה רק יכול להתמודד עם מצביעים ולא להתמודד עם מספרים שלמים 871 01:16:38,900 --> 01:16:49,240 ופשוט להיות כמו int * x = 0. 872 01:16:49,240 --> 01:16:53,000 ואז אתה הולך באמת מתבלבל פעם אחת פעולות אריתמטיות על מצביעים מתחילות לקרות. 873 01:16:53,000 --> 01:16:56,570 אז המספרים שהם בחנות הם חסרי משמעות. 874 01:16:56,570 --> 01:16:58,940 זה רק איך אתה בסופו מפרש אותם. 875 01:16:58,940 --> 01:17:02,920 אז אני חופשי להעתיק ox100 מ* int לint, 876 01:17:02,920 --> 01:17:07,790 ואני חופשי להקצות - אתה כנראה הולך צועק עליי על שלא ליהוק - 877 01:17:07,790 --> 01:17:18,160 אני חופשי להקצות משהו כמו (int *) ox1234 ל* int שרירותי זה. 878 01:17:18,160 --> 01:17:25,480 אז ox123 הוא בדיוק כמו תוקף כתובת זיכרון כפי שהיא & y. 879 01:17:25,480 --> 01:17:32,060 & Y קורה להחזיר משהו שהוא פחות או יותר ox123. 880 01:17:32,060 --> 01:17:35,430 [תלמיד] שזה יהיה ממש מגניבת דרך ללכת מהקסדצימלי לצורה עשרונית, 881 01:17:35,430 --> 01:17:39,230 כמו שאם יש לך מצביע ואתה מטיל אותה כint? 882 01:17:39,230 --> 01:17:44,860 [אודן] אתה באמת יכול פשוט להדפיס באמצעות כמו printf. 883 01:17:44,860 --> 01:17:50,300 בואו נגיד שיש לי int y = 100. 884 01:17:50,300 --> 01:18:02,700 (אז printf% d \ n - כפי שאתם כבר אמורים לדעת - להדפיס שכמספר שלם,% x. 885 01:18:02,700 --> 01:18:05,190 אנחנו פשוט להדפיס אותו כהקסדצימלי. 886 01:18:05,190 --> 01:18:10,760 אז מצביע אינו מאוחסן כההקסדצימלי, 887 01:18:10,760 --> 01:18:12,960 ושלם אינו מאוחסן כעשרוני. 888 01:18:12,960 --> 01:18:14,700 הכל מאוחסן כמו בינארי. 889 01:18:14,700 --> 01:18:17,950 זה רק שאנו נוטים להראות כמצביעים הקסדצימלי 890 01:18:17,950 --> 01:18:23,260 כי אנחנו חושבים על דברים בלוקים 4-byte אלה, 891 01:18:23,260 --> 01:18:25,390 וכתובות זיכרון נוטות להיות מוכר. 892 01:18:25,390 --> 01:18:28,890 אנחנו כמו, אם זה מתחיל עם BF, אז זה קורה להיות בערימה. 893 01:18:28,890 --> 01:18:35,560 אז זה רק הפרשנות שלנו של מצביעים כהקסדצימלי. 894 01:18:35,560 --> 01:18:39,200 אוקיי. כל השאלות אחרונות? 895 01:18:39,200 --> 01:18:41,700 >> אני אהיה כאן קצת אחרי אם יש לך משהו אחר. 896 01:18:41,700 --> 01:18:46,070 וזה סוף הסיפור. 897 01:18:46,070 --> 01:18:48,360 >> [תלמיד] יש! [מחיאות כפות] 898 01:18:51,440 --> 01:18:53,000 >> [CS50.TV]