[Powered by Google Translate] [שבוע 4, המשך] [דוד י מלאן - אוניברסיטת הרווארד] [זה CS50. - CS50.TV] זה CS50, וזה סוף השבוע 4. אז קצת חדשות טובות וחדשות רעות. אין הרצאה ביום שני, אין בעיה להגדיר בשבוע הבא. [תלמידים מריעים] אתה לא הולך לאוהב לאן זה הולך. אבל יש לנו את זה במקום ביום רביעי הבא, ויש גם להרצאת סילבוס יום שישי 1 ביום שישי הבא, כך שנוכל להישאר על מסלול. אבל הכל יהיה מצולם כרגיל, אז לא לדאוג. ובנוגע לחידון 0 מה שנעשינו לקראת סוף השבוע הוא לפרסם בדף הבית של cs50.net כמובן הסבר של איזה סוג של ציפיות צריכים להיות לך כשזה מגיע לחידון הראשון. באופן כללי, זה יהיה בחירה, תשובה אמיתית, שקר, בקיצור, בעיות קידוד קצרות. אתה לא הולך להיות צפוי ליישם את המקבילה של בעיה שהיית רואה על pset, שעבורו יש לך מחשב והבאגים וכדומה, אבל יהיו בעיות קידוד קטנות. ואכן, המדריך הטוב ביותר כדי לקבל תחושה של מה CS50 חידונים הם כמו זה ללכת cs50.net, ללכת על קישור בחנים, ואתה יכול לראות בשנים האחרונות בשווי של החידונים. רק מבין שתכנית הלימודים לא תמיד הייתה אותו לאורך השנים. לפעמים אנחנו מוסיפים, לעתים לחסר, כך שאם אתה רואה כמה נושא באחד מאלה ישנים חידונים שאין לך מושג מה הוא מדבר עליו, זה או שאנחנו לא מכסים אותו או שלא כיסה אותו. אבל בצורה של חוות דעת, ביום ראשון, השני והשלישי כמו גם חיבור כמובן רחב ביקורת יום ראשון בלילה - זמן ומיקום שהודיע ​​בעמוד הבית של הקורס - כולכם יש הזדמנות לבחון עם עמיתי ההוראה של הקורס חומר לשנה זו, היא בסעיף וככיתה מלאה, ומי יהיה צולם כרגיל גם כן. בסדר. אז בלי עיכובים נוספים, הערה אחת על עובר / נכשלה ולהוסיף / טיפה. יכול להיות שראית את הרשימות שלי אתמול בלילה, וזה באמת רק כמה חיזוקים נוספים שאם אתה בין אלה בעיקר פחות נוחים או איפשהו באמצע ואתה מרגיש קצת מעל הראש שלך, להבין שאכן די נורמלי, ויש מבנה תמיכה נרחבת במקום, אחד מהם השעות עבודה היו כוונה בשיפור עוד יותר ללילה האחרון הדוא"ל שלי, ומבינים גם שאפשרות כמו עובר / נכשלה למעמד כזה באמת נועד כמנגנון לקחת את העוקץ של קורס כזה, כך ששוב, אם אתה מבלה 10, 15, 20 השעות האלה רק מנסה להשיג קצת pset לעבודה ואתה יודע שאתה 90-95% מהדרך לשם אבל אתה לא יכול למצוא איזה חיידק ארור, בעובר / נכשלת מודל זה סוג של בסדר. הרעיון הוא שעם אותו מנגנון אז אתה יכול להתמקד בpsets האחר שלך או לישון או מה שזה לא שאתה רוצה להתמקד. אז הבנת שיש לך עד יום שלישי הקרוב - טכני ביום שני 5, אבל זה חג, אז זה יום שלישי הקרוב - כדי לעבור מעובר / נכשל ללהיפך מדורג או סגן. אם אתם ממש על שפת התהום וחושבים לעזוב לגמרי ו, אנא תתפוס אותי אחרי הרצאה או ירידה לי פתק. נשמח לפחות צ'אט בטרם הצעת אדיו. בסדר. אז התחיל לקחת את גלגלי עזר מהפעם האחרונה. בפרט, אנו מתמקדים במחרוזת. מחרוזת היא משהו שהצהיר בספריית CS50, במיוחד שבקובץ שנקרא cs50.h בו יתחילו להסתכל על השבוע הזה והבא. אבל מחרוזת היא באמת רק פישוט של משהו זה קצת יותר arcanely תאר כ* char. Char אנחנו מכירים. זה רק דמות אחת. אבל * כשל יום שני מסומן מה? >> [תלמיד] מצביע. מצביע. ומה מצביע? >> [תלמיד] כתובת. זה כמו כתובת, מיקום בזיכרון. מה כתובת או מיקום או זיכרון? שוב, לכולנו יש מחשבים ניידים עם הופעה או 2 ג'יגה בייט של זכרון RAM ככל הנראה בימים אלה, וזה אומר שיש לך מיליארדים או 2 מליארד בתים בשווי של הזיכרון. וזה לא ממש משנה מה זה פיזי נראה, אבל לקחת על אמונה שאתה יכול למספר את כל הבתים הבודדים שבמחשב נייד שלכם יש - זה ייט 0, זה הוא בית 1, זה בתים 2000000000 - וזה בדיוק מה שמחשב עושה. כשאתה להקצות שטח לתו בודד, למשל, זה ברור שצריך לחיות איפשהו בזכרון המחשב שלך, ואולי זה במספר בתי 12345, וזה איפשהו כאן בזכרון המחשב שלך. ואז הכתובת של שהדמות היא 12345. עכשיו, בשבוע 0 עד עכשיו עד כה, יש לנו לא ממש אכפת שם בדברי זיכרון מאוחסנים כי אנחנו בדרך כלל משתמשים בסמלים, משתנה, ומערכים לממש מקבלים בנתונים שלנו. אבל נכון ליום שני ועוד יותר היום, אתה עכשיו הולך להיות כל יכולות הבעה יותר עם תוכניות כתיבה באמת כדי לתפעל הזיכרון של מחשב כפי שאתה רואה לנכון, למטרות טובות ורעות, באגים להיות תוצאה נפוצה מאוד בנקודה זו בלימוד החומר הזה. אבל מה זה באמת אומר להיות * char? בואו נלך קדימה חזרה - ואנחנו נחזור לינקי כפי שהובטח היום. בואו נלך לדוגמה פשוטה כאן. בואו להציל אותי בקובץ זה כcompare.c, ותן לי רק קצת קוד תבנית כאן לכן כולל stdio.h, הרשה לי גם לתת לעצמי כולל cs50.h. אני להתקרב לשם. הרשו לי להתחיל לכתוב int הראשי, עיקרי (void), ועכשיו אני רוצה לעשות משהו כזה: printf ("תן לי את מחרוזת:") ולאחר מכן אני אשתמש במחרוזת של מקבל GetString כדי לקבל מחרוזת מהמשתמש, ואז אני הולך לשאול את המשתמש לעוד אחד. ("תן לי את מחרוזת אחרת:") ואני רוצה לשאול אותם דרך GetString לקבל את זה. אני אתקשר אליו לא משום שלא באתי אחרי זה ואת זה הוא שם יפה למחרוזת אם זה דומה למדי. אז GetString, ועכשיו אני רק רוצה לעשות בדיקת שפיות ואני הולך לומר אם (הים == t) אז אני פשוט הולך לספר את משתמש printf ("אתה הקלדת את אותו הדבר \ n"); עוד אני הולך להדפיס משהו כמו ("אתה מוקלד משהו שונה! \ n") או מה שלא יהיה המשפט. אז משהו כזה. אז כרגיל, אני אחזיר 0 שרק סמלתי ששום דבר רע לא קרה, ואני הולך קדימה, לקמפל ולהריץ תכנית זו. אבל ביום שני רצנו תכנית זו, ובעצם נאמר להם ששלום הוא לא שלום ולהתראות לא להתראות. ההתנהגות שראינו הייתה קטן יותר כמו זה. תן לי ללכת לספריית המקור שלי, זום בכאן, ובואו עושים להשוות. מלוקט בסדר. תן לי לרוץ להשוות. תן לי את מחרוזת: שלום. תן לי את מחרוזת אחרת: שלום. הקלדת משהו שונה! ובכן, תן לי לנסות משהו פשוט יותר כמו 50, 50. הקלדת משהו שונה! היי, היי. אז ברור, משהו קורה כאן. אבל מה היה ההסבר למה? ככל הנראה, הקו 12 הוא לחלוטין לא מתפקד. מה הבעיה הבסיסית כאן? כן. >> [תלמיד] זה משווה את הכתובות. כן, בדיוק. זה באמת משווה את הכתובות שבו שלום ושלום מאוחסנים. זה לא משווה את האותיות שלום שוב ושוב, כי מה שבאמת קרה, כל הזמן הזה אנחנו כבר משתמשים GetString - לוח זה הוא שוב הזיכרון של המחשב שלנו, ונניח שאני קורא GetString לאחר ההכרזה של משתנה. מה הזיכרון שלי נראה? בואו נגיד שזה שרירותי נראה כך. זה ריבוע. ופחות או יותר כל פעם שאני נמשך פיסת הזיכרון על המסך אם זה 32 ביטים אני מצייר ריבועים כמו זה, כי אכן במכשיר, מצביע, כתובת, הוא 32 סיביים. זה אותו הדבר כמו int. זה עשוי להשתנות בהתאם למערכת מחשב. אלה מכם שאינם מוכרים לו את עובדה שMac או PC שלך הוא 64 סיביים, כי בעצם מציין שהמחשב שלך תוך שימוש במצביעים 64-bit, כתובות 64-bit, ובין upsides של שהמחשבים שלך יכול להיות הרבה יותר זיכרון RAM מאשר פעם. סיפור ארוך קצרים, חזרה ביום שבו השתמשו במחשבים 32 סיביים בלבד כדי לייצג את הכתובות, המספר הגדול ביותר של בתים שיכול לייצג במקרה זה היה מה אם יש לך 32 סיבי? אז 4 מליארד דולרים, נכון, כי 2 עד 32 הם 4 מיליארדים שקל. מספר זה כבר חוזר לקורס. אז אם יש לך 32 סיביים, רק את המספר הגבוה ביותר שאתה יכול לסמוך להוא בערך 4 מליארד שקל. אבל זה היה מגבלה בסיסית של מחשבים עד לפני כמה שנים כי אם אתה יכול לסמוך גבוה כמו שרק עד 4 מיליארדים, זה לא משנה אם אתה קונה 8 ג'יגה בייט של זכרון RAM או אפילו 5 ג'יגה בייט של זכרון RAM; אתה לא יכול לספור כל כך הרבה, אז זה היה חסר תועלת. אתה יכול לגשת ל3 או 4 ג'יגה הראשונה של זכרון המחשב שלך בלבד. זה פחות בעיה עכשיו, ואתה יכול לקנות יתרונות וDells MacBook עם 8 ג'יגה RAM של או אפילו יותר בימים אלה. אבל אם אני להקצות די פשוט בתכנית זו מצביעה, מצביע הנקרא הים, זה עשוי להיראות כך על המסך, כי אכן אנחנו צריכים לקלף שכבה זו. אני שומר את המחרוזת אומרת, אבל כמו של יום שני, המחרוזת היא באמת * char, הכתובת של דמות כלשהי. אז בואו ניקח את זה גלגל אימונים את למרות שאנחנו נמשיך להשתמש GetString לעת עתה. אז אני כבר הכרזתי הים, וזה נתח של זיכרון, 32 סיביות. מה יש בזה בזיכרון כברירת מחדל? >> [תגובת תלמיד לא נשמעה] מה זה? >> [תלמיד] אשפה. זבל. >> בדיוק. אם המתכנת לא לשים ערך במשתנה, מי יודע מה זה? לפעמים יש לך מזל וזה 0, שהוא סוג של ערך ברירת מחדל נחמד, נקי, אך כפי שראינו יום שני, לפעמים זאת שטות גמורה, חלק מספר חיובי או שלילי גדול באמת שהגיע משם? כן. >> [התלמיד] הפונקציה לפני. >> כן. לעתים קרובות פונקציה שקראה לי לפני כי יזכרו, כפי שאתם קוראים פונקציות בזיכרון, הם תופסים יותר ויותר מקום מלמטה למעלה, וברגע שמחזיר הפונקציה, שמקבל זכרון שימוש חוזר על ידי הבחור הבא שקורא, שמשתמש באותה הפרוסה של זיכרון שלך. ואם יש לך את אשפה שהותיר שם, ערכים קודמים, אנחנו עלולים לטעות של כבעל ערך כלשהו, ​​אם כי בעצם לא צריך לשים שום דבר שם. אז זכרון RAM שלנו בשלב זה נראה כך. עכשיו בצד הימני של קו 7 שאנחנו קוראים GetString, שאנחנו עושים עכשיו לשבועות, אבל מה היא באמת עושה GetString? GetString נכתב על ידי צוות CS50 הוא קצת אינטליגנטי שברגע שמשתמשים מפעיל מפתחות ולהיטים להקליד Enter, GetString דמויות מתוך כמה הקשות עשתה להיט המשתמש, כמה תווים אני צריך להקצות זכרון RAM ל. ואיפה שמגיע מהזיכרון RAM, מי יודע? זה איפשהו ב2 ג'יגה או מה שלא מזיכרון של המחשב. אבל בואו נניח שהמחשב מצא מקום למילת שלום ממש כאן. המילה שהקלדתי הייתה H-E-L-L-O. ואם אנו מפנים את זה כרצף של תווים, נוכל לצייר את זה ככה. אבל אני צריך לעשות דבר נוסף 1. מה שייך בסוף כל מחרוזת ב-C? תו null, שאנו כותבים כ\ 0. טכני זה המספר 0, אבל עושה את כל הקו הנטוי ברור יותר כי זה ממש את המספר 0, 0 השלמים; זה לא, למשל 0, במרכאות, כי ייתכן שתקלידו במקלדת. אז זה שלום. ומה שאנו אומרים ביום שני כי בפונקציה כמו GetString למעשה הוא חוזר כל השבועות האלה? זה לא חוזר מחרוזת כשלעצמה משום שלא באמת יש משמעות כי מייתרים לא קיימים. הם קצת ייצור בCS50 הספרייה. מה היא באמת מחרוזת, יותר מבחינה טכנית? >> [תלמיד] זה התו הראשון. בדיוק. זה די פשוט הכתובת של התו הראשון שמשתמש הקליד פנימה אז אם המילה שלי שלום מסתיים אותו ב 123 מספר בתים ולאחר מכן במספר בתי 124, 125, 126, וכן הלאה, אם אני רק מספר הבתים שלי מ 0 ומעלה, מה באמת GetString חוזר הוא, פשוטו כמשמעו, 123 מספר. אז מה מוכנס זה הוא 123 מספר, ולא באות H, ולא במילת שלום, פשוט הכתובת שבה אני יכול למצוא את האות הראשונה של שלום. אבל זה לא נראה לך מספיק. שאלתי אותך למחרוזת, לא דמות. אז איך אנחנו או המחשב יודעים שello סוג של לבוא יחד עם H? מה הסוג של הסכם שיש לנו? כן. [תלמיד] זה כל זמן אומר לי עצמו כדי למצוא עוד כמה דמויות. >> בדיוק. יש אמנה זו מחשב האנושי לפיו כאשר יש לך עסק עם מחרוזות, הידוע כיום ככוכבי char, אתה פשוט צריך להבין איפה הסוף של כל מחרוזת בחיים הוא באמת רק על ידי iterating על זה עם ללולאה, לולאה בזמן, לא משנה מה, כך שכאשר אתה מוצא את סוף המחרוזת עכשיו אתה יכול להסיק מזה, הו, כל המילה הייתה שלום. אלה מכם עם ניסיון בתכנות מראש אולי יודעים בג'אווה אתה יכול פשוט להתקשר. אורך וגם בשפות אחרות אתה יכול לקרוא לאורך או דומה. זה בגלל בהרבה שפות, ובמיוחד דברים נקראים שפות מונחות עצמים, אורכו של דבר הוא סוג של בתוך מארז של פיסת המידע עצמו, הרבה כמו שאנחנו מזהים במארז ושמות ובתוך בתים של סטודנט ביום שני. אבל C היא רמה נמוכה בהרבה. אין אובייקטים או כיתות, אם שמעו את המונחים האלה קודם. כל מה שצריך באמת הוא כתובות זיכרון. אז זה סוג של הדרך המיושנת של ייצוג מבני נתונים מעניינים. יש לך ערך התחלה כמו הכתובת של התו הראשון ואז רק חלק מוסכמה שרירותית שכולם מסכים לעקוב אחריו. אז איך אורך מחרוזת מיושם, האם אנחנו מציעים? Strlen, strlen, שכמה מכם עכשיו השתמשו כמה פעמים. זה די פשוט, נכון? זה כמו 2 שורות קוד. זה די הרבה ללולאה כלשהי, אולי עם משתנית מקומי נוספת. אבל strlen פשוט צריך לקחת מצביע ולאחר מכן להתחיל לחפש \ 0. וברגע שהוא מוצא אותו, הוא יכול להחזיר את המספר הכולל של צעדים שננקטו בזה שחוט. אז אנחנו יכולים להסיק מזה מה שקורה בא. תניחו אם אני מצהיר לא כפי שעשיתי בקו 10. זה קצת ערך זבל. מי יודע בהתחלה? אבל בצד הימני של שורה של 10 אני מתקשר GetString שוב. מי יודע לאן זה יגיע? בואו שרירותי להגיד שמערכת ההפעלה מצאה מקום לזה בדרך לכאן. אני במקרה במקרה לסוג H-E-L-L-O שוב, וכדי שנוכל לצייר את אותו סוג של תמונה. אבל העובדה שיש לי את התמונה הזאת צוירה מחדש היא מכוונת כי זה שונה שלום יותר מזאת. אז הנה זה יכול להיות מיקום 456, זה 457, וכן הלאה. אז מה מקבל במקום של סימן השאלה שהיה בעבר? במקרה זה 456. אנחנו קולטים את המספרים האלה באופן שרירותי כי באמת שאחרי היום אנחנו לא הולכים כל כך אכפת מה הכתובת של דבר הוא. כל אכפת לנו הוא שאנחנו יכולים להבין את הכתובת של קטע מסוים של נתונים כמו שלום. אז באמת מה שרוב האנשים עושים במדעי מחשב כאשר מדברים על כתובות זיכרון ומדבר על מצביעים באופן ספציפי, ולא טרח לגלות 123 - למי אכפת איפה החומר הזה הוא למעשה, אנחנו רק יודעים שזה בחלק הכתובת מספרית - לפשטנו את העולם, ורק אומרים שזה מצביע שלאופי ולא מצביע על הדמות. והעובדה שזה חץ היא די מכוונת כי ממש עכשיו שלו מצביע על H ולא מצביע בH האחר מכיוון שבסופו של היום, זה לא משנה מה היא הכתובת, אבל זה עניין שיש לנו את היכולת להביע את הכתובה שעם חלק כלשהו של קוד. אנחנו לא באמת יש מניפולציות כתובות אלה עדיין כך אוכל לראות איפה אנחנו יכולים להתערב ולמיין של לעשות דברים עם מצביעים, אך לעת עתה בקו 12, פשוטו כמשמעו, מה ערכים שאנחנו משווים על פי הסיפור הזה בקו 12? אנחנו אומרים הוא 123 שווה שווים 456? וזה בהחלט לא מקרה. וגם רעיוני, מצביע זה בהחלט לא אותו הדבר כמו זה משום שהתקשרת GetString פעמים, וGetString אינו מנסה להיות סופר מתוחכם, זה לא לנסות להבין, הו, שהקלדת שלום לפני 5 דקות; תן לי לתת לך את אותו מצביע כמו שנתתי לך לפני, זה פשוט מקצה נתח חדש של זיכרון בכל פעם שאתה קורא לזה. אז איך לתקן את הבעיה הזו? אם רמה גבוהה יותר אני רוצה להשוות את מייתרי שלום ושלום - לא אכפת לי על המצביעים - איך אני הולך על תשובה לשאלה, לא למשתמש להקליד את אותו הדבר? מה שדרוש כאן? כן. [תלמיד] להשתמש בפונקציה. >> אני יכול להשתמש בפונקציה מחוץ לקופסה. אני יכול להשתמש בפונקציה שנקראת strcmp, s-t-r-c-מ-p, רק הגרסה המקוצרת של אומר מחרוזת להשוות. ואם אנחנו נכנסים, למשל, להשוות 2, שהוא בין דפי המידע של היום, אני עושה בדיוק את זה. שמרתי כל דבר אחר מאותו הקו 1 בעד 26 או כך, ועכשיו שם לב חלק זה השתנה קצת. בואו נתעלם מקו 28 לרגע ולהתמקד רק בזה. מה שאנחנו אומרים היום כי str compare עושה? הוא מטפל בתהליך של לקיחת 2 מצביעים, הים ולא במקרה זה, סוג של כמעט הניח את האצבע שלה על 2 המכתבים האלה, ומה עליה לעשות הוא משהו כמו לולאה בזמן או ללולאה, וזה אומר הם אלה את אותו הדבר? אם כך, זה מעביר את האצבעות או את המצביעים קדימה. האם אלה זהים, אלה זהים, אלה זהים, אלה זהים, אלה זהים? ואווה, אני בסוף המחרוזת בהן של ולא. אני לא מצאתי סתירות. כן, המחרוזות הללו הן אותו הדבר. ומה str להשוות תמורה אם 2 מחרוזות זהות, כנראה? אפס. אז 0 הם טוב במקרה זה, כי אם היא מחזירת -1 או +1, זה אומר שזה קורה רק כדי לבוא לפני לא בסדר אלפביתי או לאחר לא. ולמה שזה יהיה שימושי יש פונקציה שאומרת לך שבאה לפני מחרוזת או לאחר במילון? [תלמיד] חיפוש. >> חיפוש ומיון. אז אתה יכול לעשות דברים כמו חיפוש בינארי או מיון בועות או למזג מיון בו אתה צריך להשוות את הדברים. עד כה יש לנו סוג של לחתוך כמה פינות ודברו רק על מיון בהקשר של מספרים כי זה נחמד וקל לדבר עליו, אבל אתה בהחלט יכול להשוות מחרוזות, תפוח ובננה, כי אם התפוח ידוע לבוא לפני הבננה, באופן דומה, אתה יכול להעביר את מחרוזות בזיכרון בדיוק כמו רוב עשתה עם מעין מיזוג בוידאו ושעשינו כאן על במה עם מיון בחירה, מיון הכנסה, ומיון בועות. אז איפה עוד אנחנו יכולים לקחת את זה? בואו ננסה את זה. סוג של בואו אשכח משיעור זה לרגע ואנסה עכשיו ולהעתיק 1.c לבצע את הפעולות הבאות. בקו 21 שאני אומר משהו להדפסה, אז אני מקבל מחרוזת מהמשתמש, אז אני בודק את זה. אנחנו לא ממש נכנסנו להרגל הזה, אבל באים נעשה את זה עכשיו. בואו ממש לקלף שכבה זו. זה באמת * char. הבחור הזה הוא באמת * char. אז מה זה אומר שיש לבדוק אם של == NULL? מסתבר שכאשר אתה קורא לפונקציה כמו GetString או באופן כללי יותר פשוט לשאול את מחשב כדי לתת לך קצת זיכרון, משהו יכול להשתבש. אתה יכול להיות מטורף ושאלת את המחשב לטרה של זיכרון על ידי מבקש טריליון בייטים של זיכרון, שפשוט לא קיימים במחשב, אבל פונקציות GetString ואחרים זקוקים לדרך צעק עליך אם בקשת יותר מדי. ודרך GetString עושה את זה היא אם יש לך שאלה על זיכרון יותר מ זמין במחשב, גם אם זה הסתברות סופר, סופר נמוכה כי אף אחד מאיתנו הולכים הקלד טריליון תווים ולאחר מכן על Enter, אבל הסתברות נמוכה ככל שיהיה, אני עדיין רוצה לבדוק את זה רק במקרה, והערך המיוחד שGetString, תשובה, ופונקציות אחרות חוזר אם משהו השתבש הוא NULL בכל הכמוסות. ומה הוא NULL? NULL פשוט קורה כל כך לייצג את מצביע. זה 0 כתובת זיכרון. העולם החליט כי באופן שרירותי, אם זה הזיכרון של המחשב שלי - אתה יודע מה? - אנחנו הולכים לגנוב רק בית 1 של הזיכרון של כל מחשב, וזה מיקום 0. אנחנו הולכים לתת לו כינוי של NULL, ואנחנו הולכים למבטיחים כי אנחנו למעשה לעולם לא לשים את נתונים אמיתיים שיש כי אנחנו פשוט צריכים שרירותי ערך מיוחד, 0, NULL aka, כדי שנוכל לצעוק על משתמשים אם משהו משתבש. אחרת אתה אולי לא יודע את זה 0 מתכוונים לשים משהו כאן או זה אומר שמשהו השתבש? יש לנו את כל להסכים שדבר אמצעי NULL הוחזר, אין כתובת בפועל הוחזרה. עכשיו, הנה אני רק אימוץ האמנה האנושית שלי אני חוזר 1 מ עיקרי אם משהו משתבש. זה בגלל חזרתו של הכנס העיקרי הוא להחזיר 0 אם טוב, 1 או ערך אחר אם רע. אבל GetString וכל פונקציה העוסק בהחזרי זכרון NULL אם משהו מתקלקל. אוקיי. אז, למרבה הצער, 27 קו, סופר פשוט ככל שיהיה, נכשל לחלוטין להעתיק את המחרוזת. למה? אנחנו יכולים לראות את זה באופן בא. אני טוען בקו 27 ליצירת עותק של הים וקורא לזה לא. אז אני לא מבקש מהמשתמש 2 מחרוזות הפעם; אני רק אומר את הערך בים יש לשים בt גם כן. אז עכשיו רק כדי להדגים כיצד שבור הזה הוא, בשורת 29 ואילך מה אני עושה? קודם אני בודק אם האורך של t הוא גדול מ 0. יש איזה חוט שם. משתמש קליד משהו פנימה מהו קו 32 עושים, כנראה? [תגובה בלתי נשמעת תלמיד] ימנית. >> אתה סוג של יכול להסיק מזה מה שאמרתי שהוא עושה. אבל מבחינה טכנית, מה זה עושה? t [0] מייצג את מה? [תלמיד] דמות 0. >> [מלאן] דמות 0. או, יותר דמוי אדם, התו הראשון בt, מה שזה, H אולי במקרה זה. וtoupper עושה מה שהוא אומר. הוא מנצל את האופי של 0 t והוא משנה אותו. אז זה אומר לקחת את הדמות של 0 t, להפוך אותו לאותיות רישיות, והחזיר אותו באותו מיקום. אז אם אני מקליד שלום באותיות קטנות, זה אמור לשנות את האותיות הקטנות h ל"א אבל הבעיה היא שבקווי 35 ו 36 מה שאני עומד לעשות הוא להדפיס עבורנו זה ולא. ומה הקטע שלך? מה בעצם אני הולך לראות אם הקלדתי בשלום בכל האותיות קטנות? מה קורה ליודפס? >> [תגובת תלמיד לא נשמעה] >> מה זה? [תלמיד] ביג H והשאר קטן. >> הגדול H והשאר הקטן עבורו, או של t? [תלמיד] גם וגם. >> גם וגם. בדיוק. אז בואו לראות מה קורה כאן. תן לי ללכת קדימה ולקמפל את זה. זה COPY1, אז לעשות את COPY1. בסדר. זום פנימה תן לי ללכת קדימה ולהפעיל COPY1, Enter, תגיד משהו: שלום באותיות קטנות. זה מהוון את העותק, אבל זה כנראה גם מהוון מקורי, כי מה שקורה עכשיו בסיפור הזה? בקו 27 שלא ממש נראה שהעתקת המחרוזת, אבל למרות שאתה יכול לקוות באופן אינטואיטיבי שכדי להיות במקרה, אם אתם חושבים על התמונה הזאת, מה באמת עשיתי? חצי מהתמונה הוא אותו הדבר. אז בואו גלגל אחורה בזמן, כדי שלא עדיין לא קיים בסיפור. S יכול להתקיים בסיפור, אבל בואו אותיות קטנה שלום שלב זה. אז בואו תתקנו אותי מה אני הקלדתי ממש פנימה במקרה זה יש לנו כאן h-E-l-l-o. אנחנו לצייר אותו כרצף של תווים, לשים קווים המפרידים שלי כאן ו\ 0 שלי. אז זה המקום שאנחנו נמצאים ברגע ששורה 1 עד 24 איש, פחות או יותר, שהוצא להורג. זו תמונה של זכרוני. כשאני מגיע לקו 27, מה קורה? בדיוק כמו קודם, אני מקבל מצביע, שאני יהיה לצייר כריבוע הזה. זה נקרא לא. ומה הערך שלה כברירת מחדל? מי יודע? איזה ערך זבל. אז אני מופשט שמרחק כסימן שאלה. וברגע שהצד הימני של קו 27 מבצע, מה אני מכניס בפנים של t? אותו הדבר זה בזה. אז אם לרגע להסיר הפשטה זו של החץ ואנחנו אומרים, הו, זו כתובת עומס זיכרון 123, כשאתה אומר לא מקבל s, פסיק, אתה ממש מכניס לי 123 כאן. עכשיו, אם אנחנו סוג של לפשט את עולמנו שוב עם תמונות, מה באמת עשית רק הוסיף חץ נוסף לעולם שלך שמצביע מלא לאותה המחרוזת מדויקת. לכן, כאשר בקו 31 ו 32, אני גם יוצא על שינוי t [0], מה היא לא [0] שם נרדף לעכשיו? s [0] כך שכל מה שקורה זה. ואף על פי שזה סוג של מרגיש רמה נמוכה מעט ומסתורי וזה סוג של מרגיש אינטואיטיבית אולי זה היה צריך להיות פשוט עבד - עשיתי העתקים של דברים בעבר וזה פשוט עבד - אם אתה באמת חושב על מה שבאמת היא מחרוזת, זה * char. ובכן, מה זה? זה את הכתובת של דמות כלשהי. אז אולי זה הגיוני יותר שכשאתה מנסה לעשות משהו סופר פשוט לכאורה כמו זה, כל מה שאתה עושה הוא העתקת כתובת זיכרון. אתה לא ממש עושה שום דבר עם המחרוזת עוצמה. אז גם אם אין לך מושג איך אתה היה פותר את הבעיה בקוד, רמה גבוהה מבחינה רעיונית, מה שאנחנו צריכים לעשות על מנת להפוך את ת"א עותק אמיתי של הים, כנראה? כן. >> [תלמיד] תן אותו למיקום חדש? >> בדיוק. אנחנו צריכים לתת t מיקום חדש. אנחנו צריכים איכשהו ליצור עולם שבו אנחנו מקבלים נתח חדש של זיכרון, אשר רק למען הבהירות אני אצייר ממש מתחת לזה, אבל זה לא צריך להיות שם. אבל זה צריך להיות באותו הגודל, אז אני לצייר הקווים אנכיים האלה באותו המקום. זה בסדר אם זה כל הזבל בתחילה. מי יודע מה הייתה שם? אבל השלב 1 הולך צריך לתת לי אותה כמות זיכרון שאני צריך כדי להתאים עותק של שלום, ואז להבין איך להעתיק h כאן, הדואר כאן, אני כאן וכן הלאה. אבל את זה כבר צריך להרגיש קצת ברור גם אם חלק מהפרטים עדיין מופשט. כדי להעתיק מחרוזת זו לתוך זה, זה רק ללולאה או לולאה בזמן או משהו שאיתו הפך לעוד יותר מוכרת. אז בואו ננסה את זה. תן לי ללכת לcopy2.c. בcopy2.c יש לנו כמעט את אותה תכנית, פרט לקו 27. זה נראה קצת מורכב, אבל אם לפרק אותו חתיכה אחרי חתיכה, הצד השמאלי הוא זהה. Char * לא יוצר את הדבר הזה בזיכרון, אם כי עם סימן שאלה כי אין לנו מושג מה היא שם כברירת מחדל. בצד הימני שעכשיו אנחנו מציגים פונקצית malloc חדשה, לזיכרון יקצה, תן לי בזיכרון, וזה כנראה לוקח כמה ויכוחים, כמה דברים בתוך סוגריים? שמעתי מלמולים של 1 ו 2, אבל זה רק 1. אין פסיק, מה שאומר שיש רק דבר 1 בתוך הסוגריים. למרות שיש סוגריים אחרים, הרשו לי להדגיש מה שבפנים בסוגריים החיצוניים ביותר, וזה ביטוי זה: (Strlen (s) + 1) * sizeof (char). אז אם אנחנו באמת חושבים שזו דרכו, שזה אומר לתת לי אורך של הים. למה שאני, והוספתי 1 על האורך? >> [תגובת תלמיד לא נשמעה] בדיוק. אנו זקוקים למקום לבחור הזה בזנב, דמות 6 שאין לו משמעות באנגלית אבל האם יש משמעות מיוחדת תוכניתית. אז אנחנו צריכים + 1 עבור שבגלל תשואות strlen הציפייה האנושית של אורך, שלום או 5, זה לא נותן לך תו null הנוסף. אז להוסיף באופן ידני את זה עם + 1. ואז זה, גודל של * (char), שלא ראו את זה קודם. זה לא טכני פונקציה. זה מילת מפתח מיוחדת שרק אומרת לך מה הוא הגודל של כמה סוג נתונים במחשב כי במציאות, חלק מאיתנו יש מחשבים של 32-bit. יש לי מחשב די ישן בבית, והיא משתמשת רק 32 ביטים לייצג מצביעים. ואז אם אני עשיתי גודל של סוג נתונים, זה יכול להיות 32 סיבי. אבל אם אני משתמש במחשב המפואר החדש שלי, אני יכול לחזור ערך של 64 סיביים למשהו כמו כתובת. אז במקרה הזה, רק כדי להיות בטוח במיוחד, אנחנו לא מתכוונים למשהו קוד קשה כמו - טוב, מה הוא בגודל של פי מה שאמר לנו עד כה char? פחות או יותר יש לנו אמרנו בע"פ שזה הבית 1, וזה פחות או יותר נכון על פני הלוח. אבל שוב, הנחות נוטות להיות רע. הם מובילים לתוכנת מרכבה אם אנשים משתמשים בתוכנה שלך בדרכים שאתה לא מתכוון. אז בואו המופשט הזה משם ופשוט יותר הגנרי אומרים אני זקוק להרבה חתיכות של זיכרון וכל חתיכה של זיכרון צריכה להיות שווה ערך לגודל של דמות, שהוא בעצם שווה ל 1 במקרה הזה, אבל זה דרך כללית יותר של כתיבתו. אז אם המילה היא שלום, כמה בתים לא malloc כנראה להקצות לשלום? [תלמיד] שישה ימים. >> שישה ימים. בדיוק רב כמו שיש לנו סימני שאלה על המסך. ואז לקחת לנחש עכשיו מבוסס על ההבנה שלך GetString מה malloc כנראה לחזור? >> [תלמיד] כתובת. כתובת של מה? של הגוש הראשון של זיכרון. אין לנו מושג מה יש שם, מפני שחלק תפקיד אחר אפשר היה להשתמש בזיכרון הזה בעבר. אבל malloc, כמו GetString, מחזיר את הכתובת של הבית הראשון של זיכרון שיש להפריש עבורך. עם זאת, מה זה לא לעשות הוא למלא את הפער הזה עם תו null קו נטוי כי מסתבר שאתה יכול להשתמש malloc להקצות כל דבר: ints, מחרוזות, מערכים, צף, מבני סטודנטים. אתה יכול להשתמש בשמה הגנרי malloc לחלוטין. זה לא אכפת או צריך לדעת מה אתה הקצאת זיכרון ל. כך שזה יהיה חצוף מצד malloc לשים \ 0 בסוף כל נתח של זיכרון זה נותן לך בגלל \ 0 הדבר הזה הוא פשוט אמנה למייתרים. זה לא משמש לints, זה לא משמש לצפים, זה לא משמש לתלמידים. וכך תפס אותך עם malloc הוא שהניטל הוא לחלוטין עליך המתכנת לזכור כמה בתים שהוקציתם ולא פעם להשתמש בלולאה או לולאה בזמן ועובר את הגבול מגוש הזיכרון שניתן לכם. במילים אחרות, ברגע שאתה להקצות זיכרון, אתה לא יכול לבקש ממערכת ההפעלה, הו, דרך אגב, כמה גדול מנתח של זיכרון זה היה? זה לגמרי תלוי בך לזכור אם אתה צריך את הערך. אז בואו לראות איך אני ממשיך להשתמש בזיכרון הזה. בקו 28 ו 29 למה אני עושה את זה? סך הכל רק לבדוק את השפיות. רק למקרה שמשהו ישתבש, אני מבקש ממך כמות מטורפת של זיכרון או יש לי כל כך הרבה דברים פועלים במחשב שפשוט אין מספיק זיכרון, משהו כזה, אני לפחות רוצה לבדוק לאפס. במציאות, רוב המחשבים ינתנו לך את האשליה שכל תכנית ניתן להשתמש במכלול של זכרון RAM שלך, אבל אפילו כך, אם המשתמש מקליד בחלק המחרוזת ארוכה מטורפת אולי בגלל שהם רעים והם באמת מנסים לקרוס התכנית או הגרזן שלך לתוך זה, אתה רוצה לפחות לבדוק את ערך ההחזרה של malloc והאם זה שווה אפס. ואם כן, בואו פשוט להפסיק ברגע זה, כי אני לא יודע מה לעשות במקרה זה. כיצד ניתן להעתיק את המחרוזת? יש כמה דרכים לעשות זאת. יש str להעתיק פונקציות ב-C, אבל זה סופר פשוט לנו לעשות בדרך הישנה הזה. ראשית הרשה לי להבין מה אורכו של הים הוא. הייתי יכול לשים את זה בלולאה, אבל במקום זה אני פשוט שמתי אותו כאן לבהירות. אז n כעת מאחסן את האורך של המחרוזת המקורית, שהוא כנראה 5. ואז בלולאה עבורי אני iterating מ 0 בעד n, ועל כל איטרציה אני שם את זה [i] בתוך t [i]. אז זה מה שמשתמע עם 2 אצבעותיי המצביעות על המייתרים לפני. כמו זה ללולאה סובב ככה, אני הולך להיות העתקת h לכאן, דואר לכאן, אני לכאן בגלל זה הוא החרא, זה לא. ואז לבסוף, בקו 35 למה אני עושה את זה? אני צריך לוודא שאני לא מסיים את המחרוזת. ואני עשיתי את זה בדרך זו להיות סופר מפורש. אבל להציע, מישהו, אם אתה יכול, דרך שונה לעשות את זה. אני לא באמת צריך את קו 35. יש דרך נוספת לעשות את זה. כן. >> [תגובת תלמיד לא נשמעה] >> יגיד את זה בקול רם יותר. [תלמיד] קטן או שווה ל. >> בדיוק. אנחנו רק יכולים לומר פחות או שווים ל-n, אשר באופן כללי היה רע משום שכמעט תמיד כאשר אנו הולכים עד שווים הדבר אנחנו בונים אנחנו הולכים שלב 1 רחוק מדי. אבל זכרו, כמה בתים לא אנו מקצים? אנו הוקצינו strlen של הים, ולכן 5 + 1 עבור סכום כולל של 6. אז במקרה הזה אנחנו יכולים לעשות משהו כזה כך שאנו מעתיקים לא רק שלום, אלא גם את \ 0 בסוף מאוד. לחלופין, נוכל להשתמש בפונקציה שנקראת str להעתיק, strcpy, אבל זה לא יהיה כמעט כמו כיף. אבל זה כל מה שהיא עושה מתחת למכסת המנוע. אז לבסוף, אנחנו עושים את אותו דבר כמו קודם. אני לא להוון ואז אני טוען שהמקור נראה כך והעותק נראה ככה. אז בואו ננסה את זה עכשיו. תן לי ללכת לכאן. הפוך COPY2. אנחנו להתקרב ולהפעיל COPY2. אני הולך להקליד בשלום באותיות קטנות, ואכן אני מקבל את האותיות קטנה לשלום כמו המקורי אבל הון שלום לעותק. אבל אני לא עשיתי עדיין. אני צריך לעשות את הדבר אחרון ש1 כאן. 46 ו 47 באופן ברור הם משחררים זיכרון, אבל מה זה בעצם אומר? מה אני עושה, האם אתה חושב, על ידי קורא קו 46 וקו 47? מה השפעה של שיש? כן. [תגובת תלמיד לא נשמעה] >> בדיוק. אתה פשוט אומר לי מערכת ההפעלה, היי, תודה על הזיכרון הזה. עכשיו אתה יכול להשתמש בו למישהו אחר. והנה דוגמה מושלמת של ערכי זבל. יש לי רק זיכרון בשימוש זה כדי לכתוב את מילת שלום ב 2 מקומות, כאן, כאן, כאן, וכאן. אז זהו ש-E-l-l-O-\ 0. אבל אז אני קורא קו 46 וקו 47, ואתה יודע מה קורה שם מבחינת התמונה? בעצם, חכה, תמונה זו היא ישנה. ברגע שאנחנו עושים את העותק, הבחור הזה הוא בעצם מצביע לכאן, אז הבה ותוציא את המספרים ורק במרחק כחצים המופשט שוב. מה קורה בתמונה הזאת, כשאני מתקשר בחינם? [תגובה בלתי נשמעת תלמיד] >> אפילו לא. אם אני קורא חופשי בים ולא - סוג של שאלה מכשילה - תמונה זו אינה משתנה כלל כי לקרוא זה וקורא לא רק מספר את מערכת ההפעלה, היי, אתה יכול להשתמש בזיכרון זה שוב, אבל זה לא ישנה את זה לnull או איזו דמות מיוחדת, זה לא ישנה את זה, זה לא משנה את השעות או דואר או אני או אני או o באף אחד ממקומות לכל דבר אחר. במונחים של התמונה, ברגע שאתה קורא, שום דבר לא משתנה חופשי. ובכך טמון המקור של ערכי אשפה כי אם אז מאוחר יותר בתכנית זו ישאל את מערכת ההפעלה לזיכרון יותר עם GetString או malloc או משהו כזה ומערכת ההפעלה אומרת, בטח, יש לי עד 12 בייטים של זיכרון פשוט ששוחררו, להשתמש אלה, מה אתה עומד לקבל לידי? אתה הולך להימסר נתח של זיכרון שאנחנו בדרך כלל הייתם מצייר עם סימני שאלה, אבל מה הם סימני השאלה האלה? הם קורים להיות ש-E-l-l-o, h-E-l-l-o. אלה הם ערכי הזבל החדש שלנו ברגע שאתה לשחרר את הזיכרון הזה. יש לזה משמעות בעולם אמיתי גם כאן. זה קורה לעשות עם זכרון RAM, אבל המחשבים שלך למעשה עושה את אותו דבר עם דיסק. נידבר על זה במיוחד עם סט בעית עתיד המתמקד בזיהוי פלילי. אבל מה שקורה בפועל, אם יש לך קצת קובץ פיננסי רגיש על שולחן העבודה שלך או JPEG דל ואתה גוררים אותו לזבל שלך, מה קורה כשאתה גורר אותו לפח או לסל המחזור? אתה יודע מה אני מדבר. [שחוק] מה קורה כאשר יש לך ראיות לכך שגרר אל תוך פח האשפה או המחזור יכול? [תגובת תלמיד לא נשמעה] ובכן, כל כך זהיר. מה קורה כשאתה עושה את זה? התשובה הקצרה היא לא, נכון? קובץ רפרף או רגיש עדיין פשוט יושב שם איפשהו בכונן הקשיח. רובנו לפחות למד בדרך הקשה, כי אתה צריך לרוקן את האשפה שלך או את סל המחזור כדי למעשה מוחק קבצים. ואכן, כשאתה לוחץ לחיצה ימני או בקרה לחץ על הזבל שלך יכול או לבחור קובץ אשפה, ריקה או מה ואתה בעצם לרוקן את פח אשפה או סל המחזור, מה שקורה בפועל אז לתמונה הזאת? לא יותר מזה. כך ששום דבר שקורה בפועל בדיסק. ואם רק באופן זמני לסטות מנושא ולכתוב - I'll פשוט להשתמש בחלק האחורי של זה. אז עכשיו הסיפור משתנה מזכרון RAM, אשר בו קיימות תוכניות בזמן שאתה מפעיל אותם, לדיסק, שהוא בו הם מאוחסנים לטווח ארוך גם כאשר הכח יצא, לעת עתה - ואנחנו נחזור לזה בעתיד - בואו פשוט להעמיד פן שזה מייצג בתוך הכונן הקשיח של המחשב שלך כי עוד ביום שהיה אמור להיות דיסקים מעגליים, בדומה לדיסקטים. אז אם יש לך איזה קובץ Excel רגיש, זה עלול לקחת את הנתח הזה של זיכרון בדיסק של המחשב שלך, ואני רק ציור אותו 1s ו 0s שרירותי. בעת גרירת הקובץ כזה לפח האשפה שלך יכול או סל מחזור, ממש שום דבר לא קורה, כי אפל ומיקרוסופט פשוט החליטו פח האשפה וסל המחזור הוא באמת רק מציין מיקום זמני. אולי סופו של דבר את מערכת הפעלת תרוקן את זה בשבילך, אבל בדרך כלל, זה לא עושה כלום, לפחות עד שאתה באמת נמוך בחלל. עם זאת, כשאתה הולך לפח ריק או סל מחזור ריק, באופן דומה, שום דבר לא קורה לתמונה זו. כל מה שקורה הוא במקום אחר במחשב שלך, יש סוג כלשהו של שולחן. זה כמו סוג של סדין רמאי קטן שאומר את זה, יניח, resume.doc, כך קורות החיים שלך בקובץ Word של מיקרוסופט נהג לגור במיקום 123 בדיסק הקשיח, לא בזיכרון ולא בזכרון RAM אבל בדיסק הקשיח, וחייך הטרומיים JPEG ב456, וקובץ Excel שלך חיים ב789 או בכל מקום. כאשר אתה מוחק קבצים על ידי ריקון האשפה או סל המחזור בפועל, תמונה זו אינה משתנית. 0s ו 1s בכונן הקשיח שלך לא ילך לשום מקום. אבל טבלה זו, הנתונים הקטנים הזה של מיני, עושה שינוי. כאשר אתה מוחק את קורות החיים שלך, זה כאילו הקובץ נמחק במובן מסוים, אבל כל המחשב שבו עושה הוא לשכוח דבר שחי על הכונן הקשיח. 0s ו 1s שמרכיב את קורות החיים או כל הקבצים האחרים האלה שלך הם עדיין שלמים. אז אם אתה עשית את זה בטעות, יש עדיין הסתברות שאינה אפס שאתה יכול לשחזר את הנתונים שלך באמצעות Norton Utilities או כמה תוכנות מסחריות מטרתו בחיים היא למצוא 0s ו 1s שהתייתם סוג של, שכח כאן, אבל יצא מכאן, כך שתוכל לקבל את הנתונים חזרה. או חוקרי זיהוי פליליים במשטרה או ה-FBI למעשה היו לוקחים את כונן קשיח ובאמת נראה לדפוסים של 0s ו 1s שנראה כמו תמונות JPEG, נראה כמו קבצי Excel, ולשחזר אותם בדרך שגם אם המחשב ששכח אותם שם. כך שהדרך היחידה באמת למחוק נתונים, כפי שנדונונו בעתיד, הוא לשפשף או לנגב את הקובץ או דיסק קשיח - אתה לא באמת יכול להיפטר מ0s ו 1s כי אחרת היית מתחיל עם כונן קשיח ג'יגה והיית מגיע עם כונן קשיח מגה אם אתה כל זמן מחיקה, פשוטו כמשמעו, 0s ו 1s. אז מה היית עושה אם אתה באמת רוצה לכסות את הרצועות שלך והבעיה הבסיסית היא שיש עדיין 0s ו 1s בדיסק? אני רואה מישהו שמנופף בידות פיזית תשבור את המכשיר. זה יעבוד. [שחוק] אבל אם זה סוג של פתרון יקר, מה יהיה יותר הגיוני? כן. >> [תלמיד] דרוס אותם. >> דרוס אותם עם מה? >> [תלמיד] נתונים אחרים. נתונים אחרים. אתה יכול פשוט להחליף את הדיסק שלך עם 0s או 1s או כל 0s, כל 1s. וזה אכן מה שחלק מהתוכנה עושה. אתה יכול לקנות את תוכנה או אפילו לקבל תוכנה חופשיה, ואפילו בנה בל-Mac OS בימים אלה, פחות מכך ב-Windows, היא היכולת מאובטחת למחוק. למעשה, אם אתה רוצה את כל הריצה הביתה היום, אם יש לכם מק ולעשות את זה, אם יש לך כמה דברים באשפה שלך יכול, אתה יכול לעשות רוקןאשפה מאובטחת, שעושה בדיוק את זה. ולא רק קבצים למחוק כאן, זה לא מוחק כאן 0s ו 1s, ולא, זה פשוט משנה את כולם, למשל, ל0s ונקודה, נקודה, נקודה. אז האחת psets העתיד שלך יהיה דווקא בכוונה כדי לשחזר נתונים - תצלומים שאנו כבר נלקחנו מאנשים, מקומות ודברים בקמפוס עבורו יעשו את תמונה משפטית של כרטיס הזיכרון של מצלמה דיגיטלית, שפירושו הרעיון בדיוק - ואתה צריך להיות מאותגר דווקא למצוא את הדפוסים המייצגים תמונות JPEG בכונן הקשיח, כמו שהתלמיד לשעבר דוא"ל שקראתי לפני כמה שבועות עשו לשחזר תמונותיה של אחותו. למה שלא תיקחו הפסקה של 5 דקות הליכה כאן, ואנחנו נתאחד מחדש עם יותר בזיכרון. אז הנה מקום שבו דברים מקבלים כיפוף מוחו קצת, אבל זה צעד מאוד חזק לקראת הבנה זה עוד יותר. הנה תכנית בשם pointers.c. זה בין הקוד לדוגמא של היום. שימו לב שבשורות הראשונות, 19 עד 22, כל מה שאנחנו עושים הם משהו כמו GetString וחוזר כתובת, לאחסן אותו בים. מכאן ואילך לpset אפילו 3 אם אתה רוצה, אבל pset 4 ועל שבו אתה יכול להתחיל לקחת את גלגלי העזר האלה בעצמך, אין שום סיבה להעמיד פן שמחרוזות קיימות יותר. זה בהחלט בסדר פשוט להתחיל להגיד * char. במאמר מוסגר, באזכורים באינטרנט ובספרים שאתה יכול לעתים קרובות לראות את הכוכב בא למשתנה. אתה יכול לראות אפילו את החללים ששני הצדדים שלו. כל אלה הם פונקציונליים נכונים. לעת עתה, אם כי, אנחנו סטנדרטיזציה על גישה זו כדי להפוך סופר ברור שדמות * זה כמו לומר מצביע אופי. זה סוג הנתונים. ולאחר מכן את השם של המשתנה הוא זה במקרה זה. אז קבלתי מחרוזת ושכינינו אותו הים. ואז כאן תבחין שאני עושה קצת רמאות ממש. זה נקרא פעולות אריתמטיות על מצביעים, שהיא סוג של סופר פשוט. זה רק אומר להוסיף ולהחסיר מספרים למצביעים. אבל זה באמת עובד. תכנית זו כנראה מדפיסה תו של מחרוזת 1 לכל קו כזה שהתוצאה הסופית - רק כדי שנוכל לקלקל לאן זה הולך, להפוך את מצביעים, לרוץ מצביעים, בואו להתקרב פנימה עכשיו תן לי להקליד משהו כמו שלום וסוג הזן והוא מדפיס את הדמות 1 בכל שורה. עד לפני שנייה, היינו עושה את זה עם כיתוב סוגר מרובע. היה לנו ללולאה ואנחנו נעשה את של printf של [i] ואנחנו היינו עושים את זה שוב ושוב ושוב עם n קו נטוי בסוף כל שורה. אבל התכנית הזו היא שונה. תכנית זו משתמשת, פשוטו כמשמעו, בחשבון. אז מה קורה כאן? קודם כל, לפני שהלולאה הזו אפילו מבצעת, מה, רק שיהיה ברור, היא בעצם של? S הוא? >> [תלמיד] כתובת. >> כתובת. וזה הכתובת של, במקרה של שלום, בתו הראשון שבמילה, שהוא h. אז זה הוא, בדוגמא הספציפית הזה, הכתובת של שעות. אז מה זה אומר לעשות s + i? ובכן, אני מתחיל ב0 בזה ללולאה. אנחנו עשינו את זה פעמים רבות. אני הולך לעלות לאורכו של החוט, כנראה. אז באיטרציה הראשונה של לולאה זה, אני כמובן 0. לכן ביטוי שזה אומר שלי + - אדרבה, +0--ברור שזה רק זה. אז מה הוא * של כאן? עכשיו אנחנו משתמשים בכוכב בדרך מעט שונה. תן לי ללכת קדימה ולהיפטר מלא בגלל שאנחנו מדברים על לעשות t והעתקים של. עכשיו אנחנו רק רוצים לספר סיפור המעורב של. וכך ברגע זה, לאחר שסוג המחרוזת, העולם שלנו נראה ממש כמו שעשה לפני רק עם של אחסון הכתובת של שעות ויותר בדרך כלל מצביע על מחרוזת שלום. אם אני עכשיו עושה קו כמו * (הים + i), בואו ננסה את זה. אז * (הים + i). תן לי לפשט את זה כי זה הוא 0, אז זה * (הים +0). ובכן, חכה רגע. לפשט עוד יותר. זה * (ים). ובכן, עכשיו את הסוגריים הם סוג של טיפשים, אז עכשיו בואו רק * לעשות בנידון. אז באיטרציה הראשונה של לולאה זו, קו שמודגש, 26, הוא פחות או יותר שווה ערך להדפסה זו. מהו סוג הנתונים של * הים? בהקשר זה, כי הכוכב קורה להיות לצדו של עצמו, אבל באופן ספציפי יותר, כי אנחנו כבר לא מכריזים s, אנחנו לא יוצרים משתנים יותר, אבל אין שום אזכור לדמות * בקו 26, אין כל אזכור ממילת המפתח, אנחנו רק באמצעות משתנים בשם של, מתברר כעת הכוכבים יש מעט שונים, ויש להודות, מבלבלים משמעות. * זה אומר ללכת לכאן את הכתובת ובהדפסה של כל מה שיש. אז זה הוא כאן, * זה הוא - כמו סוג של מצנחים וסולמות, בצע את החץ - כאן. אז זה * s. אז מה מקבל מודפס על החזרה הראשונה של לולאה בקו 26? אני מדפיס את ג%, שהוא מציין המיקום עבור תו, אז \ n לשורה חדשה. * (הים + i) שבו אני הוא 0 הוא בדיוק זה. אז מה char למקם בג%? ח באיטרציה הבאה של הלולאה - כנראה שאתה יכול לראות לאן זה הולך - איטרציה הבאה אני כמובן 1, כך שזה אומר של +1, ואז עכשיו אני צריך את הסוגריים כי עכשיו הכוכב צריך לומר ללכת לכתובת זיכרון של 1. מה זה? בואו נגלגל אחורה בזמן ואומרים החץ הזה עכשיו הוא לא ממש עושה לנו טוב. תן יותר ספציפי לומר כי זה אחסון 123 מספר בגלל ההתחלה של מחרוזת זו שלום, זו כתובת 123, זה 124, וכן הלאה. אז על החזרה השנייה כשאני אומר של +1, זה כמו להגיד ש123 1, הידוע גם 124, אז מה char מקבל מודפס על החזרה השנייה? E בכתובת הזיכרון 124. ואז שוב +, 125, 126, 127, וזה לולאת שמחה מפסיקה לפני שנגיע לכאן כי אני משתמש strlen כדי לוודא שאני לא נחשב גבוה מדי. אז גם זה את זה. שוב, זה בדיוק כמו שאנחנו עשינו לפני שבוע. תן לי לכתוב את זה בשורה מתחת למרות שאנחנו לא רוצים לעשות את שניהם. זה זהה לזה עכשיו. אז למרות שזה הוא מחרוזת, כפי שכבר כינו אותו במשך שבועות, זה באמת * char. אז אם אנחנו רוצים להיות סופר אנאלי, זה באמת נכון לכתוב את התו הספציפי במיקום ה-i באמצעות כתובות אלה מספריים ומפעיל כוכבים זה, אבל בכנות, זה פשוט כל כך הרבה יותר נקי. אז זה לא רע. אין שום סיבה להפסיק לעשות את הקו 27 כאן, אך 26 הן פונקציונליים זהים, וזה תפקודי זהה בדיוק מהסיבות שאנחנו כבר דנים עד כה. ולבסוף, 29 הם בפועל רק טוב. שיחות חינם משל הפירוש שעכשיו אתה נותן בחזרה את הזיכרון שGetString נתן לך כי שוב, כפי שציינתי יום שני, GetString לשבועות כבר מציג באג בקוד שלך. הקוד שלך במשך שבועות יש לו דליפות זיכרון לפי ששאלת GetString לזיכרון, אבל אתה אף פעם לא היה נותן לו בחזרה. ושנבחר במכוון על ידי בנו מבחינה פדגוגית כי זה פשוט יותר מדי לחשוב על שלב מוקדם. אבל עכשיו אנחנו צריכים יותר סימטריה. אם אתה שואל את המחשב לזיכרון, כפי שקורה לGetString, כמו במקרה כנראה לmalloc, אתה חייב עכשיו ל4 ואילך pset גם ללא כל זיכרון כזה. שים לב זה שונה מלומר n int. אתה לא צריך לשחרר את זה, כי אתה לא קורא GetString ואתה לא קורא malloc. ואפילו אם היית קורא GetInt כפי שסופו של דבר יראה, GetInt אינו מקצה זיכרון עבורך, כי אתה בעצם יכול לעבור סביב מספרים שלמים וצוף תווים בדיוק כפי שאנחנו כבר עושים במשך שבועות. מייתרים, אם כי, הם מיוחדים בגלל שהם באמת השרשור של תווים מרובים. אז הם פשוט שונים מתווים וצף ints וכדומה. אבל אנחנו נחזור לזה לפני זמן רב. יש שאלות אז בהתחלה זה של מצביעים? כן. [שאלת תלמיד לא נשמעה] אה, שאלה טובה מאוד. אחד הדברים הבודדים C למעשה עושה בשבילך, וזה נוח, האם זה דמוי בשבילך מה גודלו של סוג הנתונים ואז עושה סוג של כפל בשבילך. זה לא רלוונטי במקרה של תווים, כי כמעט תמיד char הוא בית 1, אז זה פשוט עובד. אבל לשם דיון, אם אתה באמת היה מדפיס מספרים שלמים ואתה מנסה להדפיס את הערך כלשהו של שמצביע על מספר שלם, אתה דומה לא צריך לעשות + 4 * אני רק בגלל int הוא 4 בתים. פעולות אריתמטיות על מצביעים אומרות שC והמהדר לעשות את כל מתמטיקה זה בשבילך. כל מה שאתה צריך לדאוג הוא הספירה בסוג של התחושה האנושית. כן. [תלמיד] אם אתה מצהיר מחרוזת בתוך לולאה for, יש לך לשחרר אותו מאוחר יותר? שאלה טובה. אם הצהרת בתוך מחרוזת של ללולאה, אתה צריך לשחרר אותו מאוחר יותר? אתה רק צריך לשחרר זיכרון שאתה מקצה עם GetString או עם malloc. אז אם אתה רק רוצה לומר משהו - תן לי להכניס סוגריים מסולסלים עכשיו אז כל הקוד קשור. אם עשית משהו, גם אם buggily, כמו זה, char * t = s, אתה לא צריך לא בחינם, כי לא לא היה כרוך בכל אזכור של malloc או GetString. אם לעומת זאת אתם עשיתם את זה, GetString, אז כן, היית צריך לא חינמי. ולמעשה, הסיכוי היחיד שלך לעשות זאת הוא עכשיו בתוך לולאה זו, לאותו הנושא של היקף ששוחחנו בעבר. אחרת היה הקצאת זיכרון, הקצאת זיכרון, הקצאת זיכרון, ובסופו של התכנית בגלל שאתה מחוץ ללולאה ש, לא לא קיים, אבל אתה אף פעם לא ספרת את מערכת ההפעלה שאתה לא צריך את זה יותר זיכרון. ולא עבר זמן רב, לpset 4 או 5 אנחנו לצייד אתכם בתכנית בשם Valgrind, אשר דומה בהרוח לGDB שביש לזה במידה מסוימת של ממשק מיושן כל כך, אבל את מטרתו בחיים היא לעזור לך. וValgrind הוא תכנית שיהיה בעתיד לחפש את התוכניות שלך מחפש דליפות זיכרון, בין אם מGetString או malloc, בו יתחילו להשתמש בכל שכפי שאנו מפסיקים להשתמש CS50 הספרייה באותה המידה. אנחנו סוף הסוף עכשיו יש סוג של אוצר המילים וסוג של מודל מנטלי בתאוריה עם שכדי לפתור התכנית השבורה הזה. אז בתכנית השבורה הזה, החלפה עובדת בתוך ההחלף, אבל זה לא ממש עבד בעיקרי משום עיקרי עבר בx ו-y, כזכור, ואלו הועברו על ידי ערכים, כביכול. עותקים שלהם ניתנו להחליף. בסוף ההחלפה, ואכן ב הוחלפו, אבל כמובן X ו-Y, כפי שדנו ביום שני, לא היו. אז אני מציע בירוק כאן שמדובר למעשה בפתרון כאן. ולמעשה, לתת לי לזוז הכוכבים שלי רק כדי להיות עקבי למרות, שוב, מבחינה תפקודית זה לא משנה. בשבועות הבאים אנו נסביר מתי ולמה זה משנה. אז בירוק כרגע הוא פתרון. למען אמת, זה נראה הרבה יותר מבולגן כי יש לי את כל הכוכבים הללו. בואו להצביע לי דבר אחד. השורה העליונה כאן איפה זה אומר int * וint * b יסודו עושה את אותו הדבר כמו תמיד. הוא מכריז 2 טיעונים או פרמטרים להחלפה, הראשון שבם הוא מצביע int נקרא, השני הוא שמצביע int בשם b. דבר היחיד שחדש בשלב זה, הוא העובדה שיש לכוכב שם. מה זה אומר? לא int, b הוא לא int. היא הכתובת של int ו b הוא הכתובת של int שונה. כאן למטה, זה שבו אני מודה C מתחיל לבלבל. עכשיו אנחנו משתמשים בכוכב, אבל יש לו משמעות שונה בהקשר זה. כי אנחנו לא מכריזים מצביעים כמו שאנחנו כאן, כאן אנו ביטול הפנית דברים. אז מבחינה טכנית, את הכוכב בהקשר זה של השורה הראשונה, שנייה ושלישית תוך החלפה הוא מפעיל dereference, שרק אומר שילך לשם. אז בדיוק כפי שהאצבע שלי אחרי חץ השעות, * אמצעי להגיע לכתובת זו ולמצוא לי int שיש שם. * אמצעי b ללכת לכתובת ויעביר לי מה שיש. אז בואו לצייר מחדש את התמונה מיום השנייה כיום באמצעות מחסנית של מסגרות, אחד התחתון שהולך להיות ראשי, העליון אחת שהולך להיות עסקת ההחלף, כך שהעולם שלנו נראה, בדיוק כמו יום שני, כמו זה. הנה הוא נתח העיקרי של זיכרון שהולך לשימוש. כזכור, מיום שנייה כי התכנית פשוט הייתי 2 משתנית, אחד שנקרא X ואחד בשם Y, ואני הכנסתי את מספרי 1 ו 2 שם. עכשיו כשאני קורא להחליף כמו שאני עשיתי ביום שני, בעבר כשהשתמשתי בגרסה האדומה של תכנית זו, שנראה כמו זה, יש לי 2 פרמטרים, ו-B, ומה שאנחנו כותבים כאן וגם כאן? רק 1 ו 2, פשוטו כמשמעו, עותקים של x ו-y. היום אנחנו נשנה את זה. היום במקום לעבור בints וב אנחנו הולכים לעבור 2 כתובות ב. כתובות אלה יקרו להצביע על ints, אבל אותן כתובות לא ints עצמם. הם כתובות. זה כמו כתובת למשלוח דואר במקום. אז עכשיו אנחנו צריכים פשוט לתת לעצמי קצת יותר פרטים על המסך. זה הזיכרון של המחשב שלי כמו שזה היה כל היום. עכשיו אנחנו צריכים קצת שיטת מספור שרירותית. אז בואו רק אומרים, רק במקרה, שזאת כתובת של זיכרון 123, 124. בואו רק נגיד שזה 125, זה 126, וכן הלאה, אבל זה שרירותי לחלוטין. אנחנו רק צריכים קצת שיטת מספור בזכרוני. אז עכשיו כשאני באמת אעבור בx ו-y, אני לא מתכוון לעבור בx ו-y; אני הולך לעבור בכתובת הדואר שלו, כביכול, של x ושל y כך שמה מאוחסן כאן וכאן הוא לא 1 ו 2, אבל אם אתה יכול לראות את הטקסט הקטן שלי, את מה שעבר במקבל כאן וגם כאן? [תגובת תלמיד לא נשמעה] >> בדיוק. 123 מקבל לשים כאן ומקבל 124 לשים כאן. עכשיו, כי הייתי הכוכב בדרך הראשונה את הקו הזה כאן למעלה בראש, התכנית שלי פשוט יודעת ש123 ו 124, למרות שהם כמובן מספרים שלמים כי כל אדם יכול להבחין בכך, הם צריכים להתפרש ככתובות, כתובות מספריות. הם לא בעצמם ושל ints, הם כתובות, וזה בגלל שיש לי את במפורש את הכוכבים שם. אז עכשיו בשורה הראשונה, שנייה ושלישית שלי בקוד עצמו מה קורה כאן? בואו נצייר את שאר התמונה. Tmp הוא בדיוק כמו שזה היה ביום שני. שום דבר מיוחד tmp. זה משתנה רק 32 סיביים מקומי, ובתוך שכנראה אני אחסון הערך *. עכשיו, אם אני רק אמרתי tmp =, מה הייתי לשים כאן? >> [תלמיד] 123. 123. אבל זה לא מה שאני עושה. אני אומר tmp = *. אמצעי הכוכבים ללכת לשם. אז הנה הוא, 123. כיצד אני יכול ללכת לשם? להעמיד פן כאילו יש חץ. ובכן, זה מה שיש, 1. אז מה מאוחסן בtmp, כנראה? רק 1. אז במילים אחרות, הוא tmp * a, * אמצעים ללכת לכתובת שנמצאה כעת ב, אשר ככל הנראה 123. אוקיי, הנה אנחנו במיקום 123, אני רואה את המספר 1, אז אני הולך לשים את המספר 1 שם. עכשיו מה שאני עושה בקו 2, * = * ב? זה אחד הוא קצת יותר מעורב, כי עכשיו מה? זה 123. אז * הוא איפה? בדיוק היכן שהייתי בעבר. אז ללכת לשם. אוקיי. עכשיו, דבר אחרון, ואז סוף הסוף זה יתחיל להיות הגיוני, בתקווה, * ב פירושו מה שיש בב? 124. אז אני צריך ללכת לשם, שהוא 2. אז מה ישים שם? 2 נכנסו לכאן כי ב * נכנס *. אז אני אעשה את זה. ואתה כבר יכול לראות, אולי, שאנחנו כל כך קרובים לפתרון בעיה זו טפשה, פשוט בצורה נכונה בפעם הראשונה כי עכשיו יש לנו עדיין זוכר מה היה x, יש לנו 2 עותקים, יש להודות, של Y, אבל בשורה 3 עכשיו אומרת * ב. אז הנה ב. * אמצעי b ללכת לשם. אז איפה הוא מיקום 124? זה כנראה כאן. אז מה אני שם פה? ברור, tmp. אז עכשיו אני עושה את זה. אז יש לי 1 כאן וכאן 2. ועכשיו מה עם כל זה, 123, 124, ו1? ברגע שחוזר swap, הזיכרון הזה הוא טוב כמו אבד כי ברגע שחוזר להחלפה, מערכת ההפעלה הוא חופשי להשתמש בזיכרון זה שוב בעתיד. רק זיכרון של עיקרי בתחתית הערימה כביכול הזה נשאר. וכך סוף סוף יש גרסה עובדת עכשיו. תן לי ללכת לswap.c, ושימו לב שלאחר מכן. בחלק העליון של התכנית ששיניתי את אב הטיפוס שלי להיות int * וint * ב. אז הדבר היחיד שאני השתניתי ללכת מאדום, שהיה רע, לירוק, וזה טוב, הוא הוספתי הכוכבים האלה היום. אבל אז כאן בעצמו להחליף הייתי צריך להעתיק, להדביק את מה שהיה רק ​​בשקופית. יש לי כאן כוכב, כוכב כאן - התואם את אב הטיפוס - ואז כל הדברים האלה עכשיו יש כוכבי פרט לtmp בגלל השימוש במשתנה זמנית, אין שום דבר חדש שם. אני רק צריך אחסון זמני עבור int. אז אנחנו לא צריכים אותו כוכב שם. אנחנו פשוט צריכים את הכוכב, כך שנוכל לעבור את זה סוג של גבול שרירותי בין 2 המסגרות הללו בזיכרון של המחשב שלי. אבל הדבר האחרון שיש לשנות, ושאולי הבחין בו כבר. מה קו השני הוא כמובן שונה עכשיו? >> [תלמיד] & x. כן, אז 25 הן בשורה האחרונה של קוד אני צריך לשנות כדי שזה יעבוד. לפני שבוע וגם ביום שני 25 השורה נראתה כך, להחליף X ו-Y, וזה פשוט נשבר, כי אם אתה אומר ההחלף (x, y) אתה נותן עותקים של X ו-Y כדי להחליף, אז זה עושה את שלו, אבל אתה אף פעם לא באמת משתנה x ו-y עצמו. אז גם אם אתם אף פעם לא ראיתם את זה קודם עם אופי האמפרסנד בקוד, פשוט לקחת את ניחוש. מה האמפרסנד עושה, כנראה? [תלמיד] לוקח את הכתובת. >> לוקח את הכתובת. אז האמפרסנד אומר תן לי את הכתובת של x. מי יודע איפה זה? זה קורה להיות 123. לא אכפת לי. רק תן לי את הכתובת של x. & Y פירושו לתת לי את הכתובת של y. ובשלב זה הוא הסיפור מושלם בקנה אחד עם התמונה שציירנו לפני רגע. אז אני מודה מצביעים, בוודאי בשבילי כשהתחלתי ללמוד את זה, היו בהחלט אחד הדברים הכי הקשים לתפוס את דעתי בסביבה. אבל תבין, במיוחד כשאנו להמשיך לשחק עם דברים כאלה, אם אתה לשבור אותו לאלה סוג פשוט של הסופר אינטלקטואלי לא מעניין בעיות מעתה נע סביב מספרים, את התשובה להרבה בלבול עם מצביעים באמת ניתן לגזור מהמכניקה בסיסית מאוד האלה. הנה כתובת. ללכת לשם עם הכוכב. או לחלופין, הנה אמפרסנד. להבין מה הכתובת באמת. בסדר. אז איפה כל הזיכרון הזה מגיע? אנחנו כבר צוירנו התמונה הזאת כמה פעמים, ואני שומר מבטיח שנחזור אליו, אבל כאן הוא הייצוג של זכרון המחשב שלך זה קצת יותר מהלוח שהכותרת שלנו הוא כאן. קטע הטקסט בחלק העליון מייצג את מה ביחס לתכנית שלך? [תגובת תלמיד לא נשמעה] >> מצטער? תגיד את זה שוב. [התלמיד] התכנית בפועל. >> התכנית בפועל. אז 0s ו 1s שיש לך הידור לאחר כתיבת קוד C ולאחר מכן פועל קלאנג ולייצר עד קצות 0s ו 1s מקבל תקוע שם בזיכרון משום שכאשר אתה לוחץ לחיצה כפולה על סמל Mac או PC שלך או להפעיל פקודה כמו מריו בפקודה, 0s ו 1s מהדיסק נטען לזיכרון, כך שהמחשב יכול לתפעל אותם ולבצע אותם במהירות רבה יותר. נתונים אותחלו אז ונתונים מאותחלים, אנחנו לא מדברים הרבה על אלה, אבל אלה הם רק משתנים גלובליים. אותחל משמעות משתנים הגלובליים שנתת לערכים; לא מאותחל משמעות משתנים הגלובליים שעדיין לא נותנים לערכים. אז יש משתני הסביבה האלה שאני מניף את הידות לחלוטין, אבל הם שם, ושדברי חנויות כמו שם המשתמש שלך וסוג אחר של פרטים ברמה נמוכים יותר. אבל הפיסות העסיסיות של הפריסה של הזיכרון שלך היא הדבר הזה שנקרא המחסנית והערימה. הערימה שוב, שיהיה ברור, היא הזיכרון המשמש בכל פעם שפונקציות נקראות, בכל פעם יש משתנים מקומיים וכל פעם שיש פרמטרים שעברו בסביבה. כל זה קורה במחסנית. הגל שלא דבר עליו, אבל לקחת ניחוש מי שמשתמש בערימה. פשוט גוש אחר של זיכרון. זה קורה שיש להפיק כאן בראש, אבל זה כנס ציורי שרירותי. שכנראה כבר משתמש בזיכרון מהערימה לשבועות? טכני זה אבל בעקיפין. >> [תלמיד] GetString. GetString וmalloc. אז הנה ההבדל המהותי. אתה יודע לשבועות האחרונים כי אם אתה צריך זיכרון, רק מצהיר על משתנה. אם אתה זקוק להרבה זיכרון, להצהיר על מערך ממש בתוך הפונקציה שלך. אבל הבעיה ששמרנו פונה היא אם להצהיר על משתנה מקומי בתוך פונקציות, ברגע שחוזר לתפקד, מה קורה לזיכרון והמשתנים האלה? פשוט סוג שלו כבר לא שלך, נכון? זה פשוט נעלם סוג של מושגית. זה עדיין פיזי קיים, כמובן, אבל זה כבר לא זכותך להשתמש. זה כמובן בעייתי אם אתה רוצה לכתוב פונקציות בחיים כי בעצם להקצות זיכרון ולא להחזיר אותו באופן מיידי. מקרה לדוגמה: המטרה של GetString בחיים הוא אין לי מושג מראש עד כמה גדול של מחרוזת אני הולך להקליד במקלדת, אבל זה חייב להיות מסוגל להקצות זיכרון להחזיק דוד או שלום או כל מאמר שייתכן שהמשתמש הקליד פנימה אז GetString כבר באמצעות malloc. Malloc לכן יש שימוש לא המחסנית; במקום זאת משתמשת בדבר הזה שנקרא הערימה. אין שום דבר שונה בזיכרון. זה לא מהר או לאט יותר או משהו כזה. זה רק פיזי במקום אחר. אבל הכלל הוא שהזיכרון זה מוקצה על הערימה לעולם לא יילקח ממך עד שאתה קורא - תיקח ניחוש - בחינם. לעומת זאת, כל זיכרון שאתה מבקש במחסנית רק על ידי הכרזה על מערך או הצהרה על משתנה כמו שעשינו במשך שבועות, כי כברירת מחדל בסופו במחסנית. וזה עובד 90% מהזמן רבים, אך במקרים נדירים אלה שבו אתה רוצה להקצות זיכרון ולשמור על הסביבה, אז אתה צריך להשתמש בפונקציה כמו malloc. או יש לנו להשתמש בפונקציה כמו GetString, אשר בתורו משתמש malloc. בואו נראים לאן זה עלול להישבר ואז להציץ בינקי. אנחנו נחזור לזה בעתיד. הנה תכנית סופר פשוטה שב 2 השורות הראשונות מה הוא עושה? באנגלית, מה 2 השורות הראשונות אלה של קוד לעשות בתוך ראשיות? [תגובת תלמיד לא נשמעה] זהיר. זה לא נותן לי את הכתובת של x או y. [תלמיד] נותן עצות לints. >> טוב. תן לי 2 מצביעים למספרים שלמים. במילים אחרות, תן לי 2 נתחי זיכרון שאני שומר ציור היום, למרות שמחקתי אותו עכשיו, כריבועים. תן לי 2 גושים של זיכרון, אחד בשם x, y אחד שנקרא - מוקדם יותר התקשרתי אליהם ולא של - ומהו סוג שהנתח של זיכרון? זה הולך לאחסון כתובת. זה מסוג int *. אז הכתובת של int סופו של דבר לחיות בx, הכתובת של int סופו של דבר לחיות בy, אבל בהתחלה, מה שבפנים של x ו-y? מי יודע? ערכי זבל. אין לזה שום קשר עם מצביעים. אם אנחנו לא צריכים לשים שם משהו, מי יודע מה בעצם יש? עכשיו, x. מה קורה כאן? זה חוקי עכשיו כי x הוא מצביע. זה * int. אז זה אומר שאני יכול לשים בx הכתובת של נתח חלק מזיכרון. מה malloc לא מחזיר? מושלם, היא מחזירה את כתובות, את הכתובת של הבית הראשון בכל נתח של זיכרון. כמה בתים הוא כנראה זה הקצאה, למשל, במכשיר? מה הגודל של int? 4. אם אתה חושב שתחזור ל1 שבוע, זה לא סופר חשוב תמיד לזכור כי, אבל במקרה הזה זה שימושי לדעת, 4 בתים. אז זו הקצאה על 4 בתי הערימה וזה מחזיר את הכתובת של הראשון אליי באופן שרירותי. עכשיו, מה עושה X? * X = 42 עושים מה? אם בנקודה זו בסיפור שיש לנו X, שנראה כמו זה עם קצת ערך זבל, זה עכשיו y עם קצת ערך זבל, עכשיו בקו 3 שהוקציתי 4 בתים. תמונה זו למעשה נראית כך. או לייתר דיוק, אם זו כתובת שרירותית 123, זה מה הסיפור שלנו עכשיו נראה. * X = 42 עכשיו מה זה אומר? זה אומר ללכת ל123 כתובת ואת המספר 42 שם. אני לא צריך לצייר הקווים האלה כי אנחנו לא עושים את המייתרים. הייתי צריך פשוט כתבתי את זה ככה, ורק לצורך ההפגנה, 42 כסוג של int תופסים הרבה מקום, 4 בתים. אז זה מה שקרה שם, אבל יש בעיה עכשיו. * Y = 13. מה שהולך לקרות כאן? הבעיה היא * y בעולם המפושט רק אומר ללכת לכתובת בy. מה בy? זה קצת ערך זבל. אז בואו נניח שזה ערך זבל 5551212, משהו מטורף כזה. * אמצעי y ללכת לטפל 5551212. זה כמו כאן. זה לא קיים, למשל. אז * y מקבל 13 אמצעי שאני מנסה לצייר כאן 13. זה לא קיים. אני חרגתי מהקטע של הלוח. מה אני מקבל? שאשמת פילוח ההודעה הסודית בגלל שאני מנסה לשים בזיכרון ערך כמו 13 במקום שאינו קיימים. שאר התכנית יכול לעבוד בסדר, אבל עד שזה לא נקודה. אז בואו ננסה לספר את הסיפור הזה. אנחנו נחזור לזה פעם אחת שדברנו עליו קללה. בואו נחזור לזה, ולהשלים עם הדבר הזה שנקרא בינקי, שההיזכרות היא פרוף בסטנפורד יושב בבית ולשחק בפלסטלינה, כדי לספר את הסיפור הזה בדיוק אותה תכנית. זה רק כ 3 דקות ארוכות. כאן יש לנו בינקי. [דובר גברי בוידאו] היי בינקי, יתעורר. זה זמן בשביל כיף מצביע. [ינקי] מה זה? למד על מצביעים? או, יופי! [דובר זכר] ובכן, כדי להתחיל בעבודה, אני מניח שאנחנו הולכים צריכים כמה עצות. [ינקי] אוקיי. קוד זה מקצה 2 מצביעים אשר יכול להצביע על מספרים שלמים. [דובר זכר] אוקיי. ובכן, אני רואה את 2 מצביעים, אבל הם לא נראים שהצבעה לכל דבר. [ינקי] זה נכון. בתחילה, מצביעים אינם מצביעים על שום דבר. את הדברים שהם יצביעו לנקראים pointees, ולהגדיר אותן היא צעד נפרד. [דובר זכר] אה, נכון, נכון. ידעתי את זה. את pointees הם נפרדים. אה, אז איך אתה להקצות pointee? [ינקי] אוקיי. קוד זה מקצה pointee שלם חדש, וחלק זה מגדיר x כדי להצביע על זה. [דובר זכר] היי, זה נראה טוב יותר. אז להפוך אותו לעשות משהו. >> [ינקי] אוקיי. אני יהיה dereference x המצביע כדי לאחסן את המספר 42 לpointee. על הטריק הזה אני צריך שרביט הקסמים שלי לביטול הפניה. [דובר זכר] שרביט הקסם שלך ביטול הפניה? זה נהדר. [ינקי] זה מה שנראה כמו הקוד. אני רק להגדיר את המספר ו... [Popping צליל] [דובר זכר] היי, יראה, הנה זה הולך. אז עושה dereference על x כדלקמן החץ לגשת pointee, במקרה זה כדי לאחסן 42 שם. היי, נסה להשתמש בו כדי לאחסן את המספר 13 באמצעות מצביע האחר, y. [ינקי] אוקיי. אני פשוט אלך לכאן כדי לקבל את y והמספר 13 הקים ואז לקחת את השרביט של ביטול הפניה ופשוט ... [זמזום] וואו! [דובר זכר] הו היי, זה לא עבד. תגיד, בינקי, אני לא חושב שביטול הפנית y הוא רעיון טוב בגלל הגדרת pointee היא צעד נפרד ואני לא חושב שאי פעם עשינו את זה. [ינקי] הממ, נקודה טובה. [דובר זכר] כן. אנחנו הקצינו את y המצביע אבל לא להגדיר אותו כדי להצביע על pointee. [ינקי] הממ, אדוק ביותר. [דובר זכר] היי, אתה נראה טוב שם, בינקי. אתה יכול לתקן אותו כך שנקודתי y לאותו pointee כ x? >> [ינקי] בטח. אני אשתמש שרביט הקסמים שלי למשימת מצביע. [דובר זכר] זאת הולכת להיות בעיה כמו בעבר? [ינקי] לא, זה לא נוגע לpointees. זה פשוט משנה את מצביע אחד למצביע על אותו הדבר כמו אחר. [Popping צליל] [דובר זכר] הו, אני רואה. עכשיו נקודתי y לאותו המקום כמו x. אז תחכה. עכשיו y הוא קבוע. יש pointee. אז אתה יכול לנסות את השרביט של ביטול הפניה שוב לשלוח 13 מעל. [ינקי] אה, בסדר. הנה זה בא. [Popping צליל] [דובר זכר] היי, תראה את זה. עכשיו עובד על ביטול הפנית y. ומכיוון שהמצביעים משתפים שpointee אחד, שניהם רואים 13. [ינקי] כן, שיתוף. לא משנה מה. אז אנחנו הולכים להתחלף עכשיו? [דובר זכר] אה, יראה, נגמרנו לנו זמן. >> [ינקי] אבל - [דובר זכר] רק יזכור את 3 כללים המצביעים. מספר 1, המבנה הבסיסי הוא שיש לך ומצביע הוא מצביע אל pointee. אבל המצביע וpointee הם נפרדים, והטעות הנפוצה היא להגדיר מצביע אבל לשכוח לתת לזה pointee. מספר 2, ביטול הפנית המצביע מתחיל במצביע ועוקב אחריה במשך החץ כדי לגשת pointee. כפי שכולנו יודעים, זה עובד רק אם יש pointee, איזה סוג של חוזר לכלל מס '1. מספר 3, הקצאת מצביע לוקח מצביע אחד ומשנה אותו להצביע לאותו pointee כמצביע אחר. אז אחרי המשימה, את 2 המצביעים יצביעו לאותו pointee. לפעמים זה נקרא שיתוף. וזה כל מה שיש בו באמת. להתראות. זה בינקי. זה CS50. ניראה אותך בשבוע הבא. [מחיאות כפות] [CS50.TV]