[השמעת מוסיקה] דאג LLOYD: אישור כך הצעה לפני שמתחיל כאן. אם לא צפה בסרטון על pointers אולי כדאי לך לעשות זאת ראשונה. בגלל הסרטון הזה הוא עוד דרך של עבודה עם מצביעים. אז זה הולך לדבר על כמה מושגים שאנו מכסים ב pointers וידאו, ואנחנו הולך לחפות עליהם עכשיו, בהנחה שהם כבר הבין סוג של. אז זה רק האזהרה הוגנת שלך כי אם אתה רואה בסרטון זה ולא ראית וידאו מצביעים, אולי זה סוג של לטוס מעל הראש שלך קצת. ואז זה יכול להיות טוב יותר כדי לצפות בו על מנת ש. אז יש לנו כבר ראיתי אחד דרך לעבודה עם מצביעים, אשר אנו מצהירים משתנה, ואז אנחנו להכריז משתנה אחר, מצביע משתנים, המצביע על זה. אז יצרנו משתנה עם שם, יש לנו יצר משתנים שני עם שם, ואנו מצביעים כי משתנה שני שבראשון. זה סוג של יש בעיה אם כי, משום שהיא דורש מאתנו יודע בדיוק כמה זיכרון אנחנו הולך צריך הרגע התכנית שלנו היא הידור. למה? כי אנחנו צריכים להיות מסוגלים לקרוא או לזהות את כל המשתנים האפשריים אנו עלולים להיתקל. אולי יש לנו מערך שעשויה להיות תוכל להחזיק הרבה מידע, אבל זה עדיין לא מדויק מספיק בדיוק. מה אם אנחנו לא יודעים, מה אם אין לנו מושג כמה אנחנו צריכים בזמן ההידור? או מה אם התכנית שלנו לרוץ במשך זמן ארוך מאוד, קבלת משתמש שונים הנתונים, ואנחנו לא יכולים באמת להעריך אם אנחנו תצטרך 1,000 יחידות? זה לא כמו שאנחנו יכולים אומרים בשורת הפקודה הכנס כמה פריטים אתה חושב שאתה צריך. ובכן מה אם מניח שזה לא בסדר? הקצאת זיכרון דינמית סוג של מאפשר לנו את הדרך לעקוף בעיה זו בפרט. והדרך שהיא עושה את זה הוא על ידי שימוש במצביעים. אנחנו יכולים להשתמש במצביעים ל לקבל גישה לדינמית זיכרון שהוקצה, זיכרון שהוא שהוקצה כתכנית שלך פועל. זה לא שהוקצה בזמן ההידור. כאשר אתה באופן דינמי להקצות זיכרון זה מגיע מברכה זיכרון ידוע כערימה. בעבר כל הזיכרון שיש לנו עובד עם בקורס כבר מגיע מברכה זיכרון ידוע כערימה. דרך טובה בדרך כלל לשמור על שלטון mind-- וזה לא תמיד להחזיק נכון, אבל פחות או יותר כמעט תמיד מחזיק true-- הוא שכל זמן שאתה נותן שם משתנה זה כנראה גר בערימה. וכל פעם שאתה עושה לא לתת משתנה שם, שבו אתה יכול לעשות עם זיכרון דינמי הקצאה, הוא חי בערימה. עכשיו אני סוג של הצגה זו כ אם יש שתי בריכות של זיכרון אלה. אבל אתה יכול לראות את זה תרשים, שהוא בדרך כלל ייצוג של מה נראה כמו זיכרון, ואנחנו לא הולכים לאכפת כל הדברים בראש והתחתון. מה אכפת לנו הוא חלק זה ב האמצע כאן, ערימה ומחסנית. כפי שניתן לראות על ידי מסתכל על תרשים זה, אלה הם למעשה לא שתיים בריכות נפרדות של זיכרון. זה בריכה משותפת אחד של זיכרון שבו אתה מתחיל, בזה חזותי אתה מתחיל בתחתית ולהתחיל למלא את מתחתית עם הערימה, ואתה להתחיל בראש ולהתחיל למלא את מלמעלה למטה עם הערימה. אבל זה באמת אותו בריכה, זה רק כתמים שונים, במקומות שונים בזיכרון כי הם הוקצו. ואתה יכול לרוץ מ זיכרון או על ידי בעל הערימה ללכת את כל הדרך לתחתית, או שיש לי הערימה ללכת את כל הדרך לפסגה, או שיש ערימה והמחסנית נפגש אחד נגד השני. כל אלה יכולים להיות תנאים שגורם לתכנית שלך נגמרים של זיכרון. אז לשמור את זה בחשבון. כאשר אנו מדברים על הערימה והמחסנית אנחנו באמת מדברים אותו נתח כללי של זיכרון, רק חלקים שונים של זיכרון ש. אז איך אנחנו מקבלים באופן דינמי הוקצה זיכרון במקום הראשון? איך התכנית שלנו אינה מקבלת זיכרון זה פועל? ובכן C מספק פונקציה שנקראת malloc, Allocator זיכרון, ש אתה מבצע שיחה ל, ואתה עובר ב כמה בתים של זיכרון שאתה רוצה. אז אם התכנית שלך פועלת ואתה רוצה ריצה שלם, ייתכן שמאלוק ארבעה בתים של זיכרון, malloc סוגר ארבעה. מאלוק יעבור מחפש דרך הערימה, בגלל שאנחנו באופן דינמי הקצאת זיכרון, והוא יחזור אליך מצביע לזיכרון ש. זה לא נותן לך memory-- ש זה לא נותן לו שם, זה נותן לך מצביע לזה. ואז זה למה שוב אמרתי שזה חשוב לאולי צופה ראה וידאו המצביעים לפני שאנחנו מקבלים יותר מדי לזה. אז malloc הולך אתן לך בחזרה מצביע. אם מאלוק לא יכול לתת לך כל זיכרון, כי אתה כבר נגמר, זה ייתן לך בחזרה מצביע null. אתה זוכר מה קורה אם אנחנו לנסות וdereference מצביע null? אנחנו סובלים אשמת SEG, נכון? זה כנראה לא טוב. אז בכל פעם שאתה מבצע שיחה לmalloc אתה תמיד, תמיד צריך לבדוק אם או לא מצביע זה נתן לך בחזרה הוא null. אם כן, אתה צריך לשים קץ לתכנית שלך כי אם אתה מנסה וdereference מצביע null אתה הולך לסבול אשמת פילוח והתכנית שלך היא הולך להתרסק בכל מקרה. אז איך אנחנו סטטי להשיג מספר שלם? x int. כנראה שעשינו ש חבורה של פעמים, נכון? זה יוצר משתנה בשם x שחי בערימה. איך אנחנו דינמי אין לקבל מספר שלם? px כוכב int שווה malloc 4. או יותר נכון היינו אומר px כוכב int שווה גודל malloc של int, רק כדי לזרוק כמה פחות מספרי קסם סביב התכנית שלנו. זה הולך להשיג לנו ארבעה בתים של זיכרון מהערימה, והמצביע שאנו מקבלים בחזרה לזה נקרא פיקסלים. ואז בדיוק כפי שיש לנו נעשה בעברנו יכול dereference px ל גישה לזיכרון ש. איך אנחנו מקבלים מספר שלם מהמשתמש? אנחנו יכולים לומר int x שווה לקבל int. זה די פשוט. מה אם אנחנו רוצים ליצור מערך של x צף שגרים בערימה? לצוף stack_array-- זה השם של x בסוגריים מרובעים array--. שייצור עבורנו מערך של x צף שגרים בערימה. אנחנו יכולים ליצור מערך של צף שחי בערימה, מדי. התחביר עשוי להיראות קצת מסורבל יותר, אבל אנו יכולים לומר לצוף heap_array הכוכב שווה פעמים x malloc הגודל של המצוף. אני צריך מספיק מקום להחזיק x ערכי נקודה צפה. אז אומר שאני צריך 100 צף, צף או 1,000. אז במקרה שזה יהיה 400 בתים עבור 100 צף, או 4,000 בתים עבור 1,000 צף, משום שכל אחד לוקח את המצוף ארבעה בתים של שטח. אחרי שעשה את זה לא יכול להשתמש ב תחביר הסוגר מרובע על heap_array. בדיוק כמו שאני היית עושה בstack_array, אני תוכל לגשת למרכיביו בנפרד heap_array באמצעות אפס, heap_array אחד. אבל זוכר את הסיבה שאנחנו יכולים לעשות את זה סיבה לכך הוא שמו של מערך ב- C הוא באמת מצביע ל האלמנט הראשון של מערך זה. אז העובדה שאנחנו מכריזים מערך של צף בערימה כאן הוא למעשה קצת מטעה. אנחנו באמת נמצאים ב קו שני של קוד שם גם יצירת מצביע לנתח של זיכרון שאז לעשות קצת עבודה עם. הנה הבעיה הגדולה עם דינמי שהוקצה זיכרון כי, וזה למה זה באמת חשוב לפתח כמה הרגלים טובים כאשר אתה עובד עם זה. שלא כמו הכריז באופן סטטי זיכרון, הזיכרון שלך לא באופן אוטומטי חזר ל מערכת כאשר הפונקציה שלך נעשה. אז אם יש לנו עיקרי, ו עיקרי קורא פונקציה F, כאשר F גימורים מה שזה עושה ומחזיר את שליטה על התכנית בחזרה לעיקרי, בכל הזיכרון ו ששמש ניתן בחזרה. ניתן להשתמש בו שוב על ידי תכנית אחרת, או תפקיד אחר ש מקבל נקרא מאוחר יותר בעיקרי. הוא יכול להשתמש על אותו זיכרון שוב. אם אתה באופן דינמי להקצות זיכרון למרות ש אתה צריך להגיד במפורש מערכת שתסיים עם זה. זה יהיה להחזיק את זה בשבילך, אשר יכול להוביל לבעיה שלך הולך ואוזל של זיכרון. ואכן לפעמים אנחנו מתייחסים לזה כדליפת זיכרון. ולפעמים דליפות זיכרון אלה באמת יכול להיות ממש הרסני לביצועי מערכת. אם אתה משתמש באינטרנט תכוף אולי אתה משתמש בדפדפני אינטרנט מסוימים, ואני לא לנקוב בשמות כאן, אבל יש כמה דפדפני אינטרנט שם בחוץ כי ידועים לשמצה שיש למעשה דליפות זיכרון שלא מקבל קבועה. ואם אתה משאיר את הדפדפן שלך פתוח לתקופה ארוכה מאוד של זמן, ימים וימים, או שבועות, לפעמים אתה ייתכן שיבחין שהמערכת שלך הוא פועל ממש, ממש לאט. והסיבה לכך היא ש הדפדפן הקצה זיכרון, אבל אז לא אמר לי המערכת שעושה את זה עם זה. וכך זה משאיר פחות זיכרון זמין לכל תוכניות האחרות שלך יש לחלוק, כי אתה leaking-- שדפדפן האינטרנט תכנית דולפת זיכרון. איך אנחנו נותנים בחזרה זיכרון לאחר שנסיים עם זה? ובכן, למרבה המזל זה דרך קלה מאוד לעשות את זה. אנחנו פשוט לשחרר אותו. יש פונקציה שנקראת חופשי, היא מקבלת מצביע לזיכרון, ואנחנו טובים ללכת. אז בואו נגיד שאנחנו ב אמצע התכנית שלנו, אנחנו רוצים malloc 50 תווים. אנחנו רוצים malloc מערך שיכול מסוגלים להחזיק 50 תווים. וכאשר אנחנו מקבלים מצביע חזרה ל כי שם, של המצביע שהוא מילה. אנחנו עושים כל מה שאנחנו הולך לעשות עם מילה, ואז כשאנחנו עשיתי בדיוק אנחנו לשחרר אותו. ועכשיו יש לנו 50 חזרו אלה בתים של זיכרון בחזרה למערכת. תפקיד אחר יכול להשתמש בם. אנחנו לא צריכים לדאוג סובלים דליפת זיכרון כי יש לנו שחררה את המילה. אנחנו נתנו את הזיכרון בחזרה, אז סיימנו לעבוד עם זה. אז יש שלוש כללי זהב שצריך לזכור בכל פעם שאתה דינמי הקצאת זיכרון עם malloc. כל בלוק של זיכרון ש אתה malloc חייב להיות משוחרר לפני התכנית שלך מסיים את פעולתו. עכשיו שוב, במכשיר או ב IDE קורה זה סוג של לך בכל מקרה כאשר אתם-- זה יקרה בכל מקרה כאשר התכנית שלך תסתיים, כל הזיכרון ישוחרר. אבל זה קידוד טוב בדרך כלל בפועל תמיד, כשתסיים, לשחרר את מה שיש לך mallocd. שאמרו, רק דברים ש יש לך mallocd צריך להיות משוחרר. אם אתה באופן סטטי להכריז מספר שלם, int x נקודת פסיק, שחי בערימה, ש לא אז רוצה לשחרר את x. דברים אז רק שיש לך צריך להיות משוחרר mallocd. ולבסוף, לא משהו בחינם פעמיים. שיכול להוביל ל עוד מצב מוזר. אז כל מה שיש לך mallocd יש להשתחרר. דברים היחידים שיש לך malloc צריך להיות משוחרר. ולא משהו בחינם פעמיים. אז בואו נלך דרך דוגמא כאן של מה שחלק שהוקצה באופן דינמי זיכרון עשוי להיראות מעורב עם כמה זיכרון סטטי. מה שעלול לקרות כאן? תראה אם ​​אתה יכול לעקוב אחר לאורך ונחש מה זה יקרה כמו שאנחנו הולכים דרך כל שורות הקוד האלה. אז אנחנו אומרים מ 'int. מה קורה כאן? ובכן, זה די פשוט. אני יוצר משתנה שלם שנקרא מ '. אני צובע את זה ירוק, כי זה הצבע כי אני משתמש כשאני מדבר על שלם משתנה. זה תיבה. זה נקרא מ ', ואתה יכול מספרים שלמים חנות בתוכו. מה אם אני אומר אז int כוכב? טוב, זה די דומה. אני יוצר תיבה בשם. זה מסוגל int האחזקה כוכבים, מצביעים למספרים שלמים. אז אני צביעתו ירוק-איש גם כן. אני יודע שיש לו משהו לעשות עם שלם, אבל זה לא את עצמו שלם. אבל זה פחות או יותר על אותו הרעיון. יצרתי תיבה. שני אלה הנכונים חיים כיום בערימה. נתתי להם את שני השמות. כוכב int ב שווה גודל malloc של int. אחד זה יכול להיות קצת מסובך. קח שני וחושב על מה שאתה היה מצפה שיקרה בתרשים זה. כוכב int ב שווה גודל malloc של int. ובכן, זה לא פשוט ליצור תיבה אחת. זה בעצם יוצר שתי תיבות. והוא קושר, הוא גם קובע נקודה במערכת יחסים. אנחנו כבר הוקצו בלוק אחד זיכרון בערימה. שימו לב שהתיבה הימנית העליונה יש אין שם. אנו mallocd זה. היא קיימת בערימה. אבל יש ב שם. זה משתנה מצביע נקרא ב. שחי בערימה. אז זה חתיכת הזיכרון שמצביע על עוד אחד. ב מכיל את הכתובת של בלוק של זיכרון. זה לא חייב שם אחר. אבל זה מצביע על זה. לכן, כאשר אנו אומרים כוכב int ב שווה גודל malloc של int, שממש שם, חץ שצץ ב צד ימין שם, כי כל דבר, אני אצטרך אותו להופיע שוב, זה מה שקורה. כל זה קורה ב ששורה אחת של קוד. עכשיו נהיה לנו קצת יותר פשוט שוב. שווה מ 'אמפרסנד. האם אתה זוכר מה שווה מ 'אמפרסנד הוא? טוב, זה מקבל את כתובתו של מטר. או לשים יותר בתרשים, נקודות למ '. שווה ב. אוקי אז הנה עוד אחד. שווה ב. מה הולך לקרות בתרשים זה זמן? ובכן זוכר ש עבודות מפעיל משימה על ידי הקצאת הערך ב זכות הערך בצד השמאל. אז במקום הצבעה למ ', עכשיו מצביע לאותו המקום שנקודות ב. אינו מצביע ל- B, מציין נקודות שבן ב. אם מחודד לב 'שהיית היה שווה אמפרסנד ב. אבל במקום שווה ב רק משמעות הדבר היא כי ב ועכשיו מצביע לאותה הכתובת, כי בתוך b הוא רק כתובת. ועכשיו בתוך היא באותה הכתובת. מ 'שווה 10, כנראה רוב הדבר פשוט שעשינו בקצת. שים 10 בתיבה. כוכבים ב שווה מ 'בתוספת 2, זוכרים מ וידאו מצביעים מה הכוכב ב אומר. אנחנו הולכים ב dereference ומכר כמה ערך שבמיקום הזיכרון. במקרה זה 12. לכן, כאשר אנו dereference נקודה זוכר רק שאנחנו נוסעים במורד החץ. או במילים אחרת, אנחנו ללכת כי כתובת הזיכרון ואנחנו יכולים לשנות אותו בדרך כלשהי. שמנו כמה ערך שם. בב כוכב מקרה זה שווה מ 'בתוספת 2 הוא רק ללכת למשתנה הצביע על ידי ב, ללכת לזיכרון הצביע על ידי ב, ולשים מ 'בתוספת 2 שם, 12. עכשיו אני חופשי ב. מה קורה כשאני משחרר ב? זוכר מה אמרתי אמצעי תשלום. מה שאני אומר כשאני לשחרר ב? אני מסיים לעבוד איתו, נכון? אני בעצם לוותר על הזיכרון. אני נותן אותו בחזרה למערכת. אני לא צריך את זה יותר מה אני אומר להם, בסדר? עכשיו, אם אני אומר כוכב שווה 11 כנראה שאתה יכול כבר אמרתי לי משהו שרע הולך לקרות כאן, נכון? ואכן, אם ניסיתי את זה אני כנראה יסבול אשמת פילוח. כי עכשיו, למרות ש בעבר נתח זה של זיכרון היה משהו שהיה לי גישה ל, בשלב זה עכשיו אני גישה לזיכרון ש אינו חוקי עבורי לגשת. וכפי שכנראה יהיה זוכר, כאשר אנו ניגשים לזיכרון כי אנחנו לא אמורים לגעת, זה הגורם הנפוץ ביותר של פילוח דופי. וכך התכנית שלי יתרסק אם ניסיתי לעשות את זה. אז שוב שזה רעיון טוב כדי לקבל טוב הרגלי תרגול וטובים טבועים בעת עבודה עם malloc וחופשי, כך שאתה לא סובל פילוח תקלות, ושאתה משתמש ב שלך שהוקצה באופן דינמי זיכרון באחריות. אני דאג לויד זה CS50.