>> [השמעת מוסיקה]
>> דאג LLOYD: מצביעים, אנחנו כאן.
זה כנראה הולך ל להיות הנושא הקשה ביותר
שאנחנו מדברים על בCS50.
ואם יצאת לך לקרוא שום דבר על מצביעים
לפני שאתה עלול להיות קצת מפחיד להיכנס לווידאו הזה.
זה נכון המצביעים אל תאפשר לך את היכולת
לפשל אולי די קשה כשאתה
עבודה עם משתנים, ונתונים, וגורם לתכנית שלך לקרוס.
אבל הם ממש ממש שימושיים והם מאפשרים לנו דרך גדולה באמת
להעביר נתונים הלוך ו שוב בין פונקציות,
שאנחנו בדרך אחרת לא יכולים לעשות.
>> ואז מה שאנחנו באמת רוצה לעשות כאן היא רכבת
ליש לך משמעת מצביע טובה, כל כך שאתה יכול להשתמש במצביעים ביעילות
כדי להפוך את התוכניות שלך, כי הרבה יותר טובים.
כפי שאמרתי מצביעים לתת השונים דרך להעביר נתונים בין פונקציות.
עכשיו, אם אתה זוכר מ וידאו קודם לכן, כאשר
אנחנו מדברים על היקף משתנה, שציינתי
כי כל הנתונים שאנו עוברים בין פונקציות בC מועברת על ידי ערך.
ואולי אני לא השתמשתי שב טווח, מה שהתכוונתי שם
היה שאנו מעבירים עותקים של נתונים.
כאשר אנו עוברים משתנים לפונקציה, אנחנו לא ממש עוברים משתנים
לפונקציה, נכון?
אנחנו עוברים עותק של נתונים שלפונקציה.
הפונקציה עושה מה שהוא יהיה והיא מחשבת כמה ערך,
ואולי אנו משתמשים ערך ש כאשר הוא נותן אותו בחזרה.
>> היה חריג אחד ל כלל זה של העברה לפי ערך,
ואנחנו נחזור למה ש קצת מאוחר יותר בסרט הזה.
אם אנחנו משתמשים במצביעים במקום שימוש במשתנים,
או במקום להשתמש במשתנים בעצמם או העתקים של המשתנים,
עכשיו אנחנו יכולים להעביר את המשתנים סביב בין פונקציות בצורה שונה.
משמעות דבר היא שאם אנחנו עושים שינוי בתפקוד אחד,
שינוי זה בעצם לקחת אפקט בתפקיד שונה.
שוב, זה משהו ש לא יכולתי לעשות בעבר,
ואם אי פעם ניסו להחליף ערך של שני משתנים בפונקציה,
שמת לב לבעיה זו סוג של זחילה, נכון?
>> אם אנחנו רוצים להחליף X ו- Y, ואנחנו להעביר אותם לפונקציה שנקראת החלפה,
בתוך הפונקציה להחליף משתנים לעשות ערכי חליפין.
אחד הופך לשתיים, שני הופכים אחד, אבל אנחנו לא ממש
לשנות משהו במקור פונקציה, במתקשר.
כי אנחנו לא יכולים, אנחנו רק עבודה עם עותקים שלהם.
עם מצביעים אם כי, אנחנו יכולים למעשה עובר X ​​ו- Y לפונקציה.
פונקציה שיכולה לעשות משהו איתם.
וערכי משתנים אלה באמת יכול לשנות.
אז זה די שינוי ב היכולת שלנו לעבוד עם נתונים.
>> לפני שנצלול ל מצביעים, אני חושב שזה שווה
לוקח לכמה דקות לחזור ליסודות כאן.
ויש להסתכל על איך עבודות זיכרון מחשב
משום ששני נושאים אלה הולכים להיות בעצם די קשורים.
כפי שאתה בוודאי יודע, על מערכת המחשב שלך
יש לך כונן קשיח או אולי כונן מצב מוצק,
איזה מיקום אחסון קבצים.
זה בדרך כלל אי ​​שם ב שכונה של 250 ג'יגה-בתים
לאולי כמה טרה עכשיו.
וזה שבו כולכם קבצי סופו של דבר לחיות,
גם כאשר המחשב סגור את, אתה יכול להפעיל אותו מחדש
ואתה תמצא את הקבצים שלך נמצאים שם שוב כאשר אתה לאתחל את המערכת.
אבל כונני דיסקים, כמו כונן דיסק קשיח, HDD, או כונן מצב מוצק, SSD,
הם שטח אחסון פשוט.
>> אנחנו לא באמת יכולים לעשות משהו עם נתונים שנמצאים בדיסק קשיח,
או בכונן מצב מוצק.
כדי לשנות בפועל נתונים או להזיז אותו מסביב,
אנחנו צריכים להעביר אותה ל זיכרון RAM, זיכרון גישה אקראי.
עכשיו RAM, יש לך הרבה פחות במחשב שלך.
ייתכן שיש לך אי שם ב שכונה של 512 מגה בייט
אם יש לך מחשב ישן יותר, לאולי שתיים, ארבעה, שמונה, 16,
אולי אפילו קצת יותר, ג 'ייגה של זיכרון RAM.
אז זה הרבה יותר קטן, אבל זה שבו כל הנתונים ההפכפכים קיים.
זה שבו אנחנו יכולים לשנות דברים.
אבל כאשר אנחנו לכבות את המחשב שלנו, כל הנתונים בזכרון RAM נהרס.
>> אז בגלל זה אנחנו צריכים דיסק קשיח למיקום קבוע יותר מזה,
כך שזה היה exists- להיות ממש רע אם בכל פעם ש
הפכתי את המחשב שלנו, כל קובץ במערכת שלנו נמחק.
אז אנחנו עובדים בתוך של זיכרון RAM.
ובכל פעם שאנחנו מדברים זיכרון, פחות או יותר, בCS50,
על זיכרון RAM, דיסק קשיח לא שאנחנו מדברים.
>> לכן, כאשר אנחנו עוברים דברים בזיכרון, זה לוקח כמות מסוימת של שטח.
כל סוגי הנתונים ש אנחנו עובדים עם
תופס שונה כמויות של שטח בזכרון RAM.
אז בכל פעם שאתה יוצר מספר שלם ארבעה בתים משתנים, של זיכרון
הם מניחים בצד בזכרון RAM, כך ש יכול לעבוד עם מספר שלם ש.
אתה יכול להכריז על המספר השלם, לשנות אותו, להקצות אותו
לערך 10 מוגדל על ידי אחד, כן הלאה וכן הלאה.
כל מה שצריך לקרות ב זיכרון RAM, ואתה מקבל ארבעה בתים
לעבוד עם כל מספר שלם שאתה יוצר.
>> כל דמותך ליצור מקבל בית אחד.
זה בדיוק כמה מקום הוא צריך לאחסן אופי.
כל לצוף, אמיתי מספר, מקבל ארבעה בתים
אלא אם כן זה כפול נקודה צפה דיוק
מספר, שמאפשר לך יש ספרות מדויקת יותר או יותר
לאחר הנקודה העשרונית מבלי לאבד דיוק,
אשר תופסים שמונה בתים של זיכרון.
מתגעגע ארוך, מספרים שלמים גדולים באמת, גם לקחת שמונה בתים של זיכרון.
כמה בתים של זיכרון אל מיתרים תופסים?
ובכן בואו לשים סיכה בשאלה ש לעת עתה, אבל אנחנו נחזור אליו.
>> אז בחזרה לרעיון הזה של זיכרון כ מערך גדול של תאים בייט בגודל.
זה באמת כל זה הוא, זה רק מערך של תאים ענק,
בדיוק כמו כל מערך אחר ש אתה מכיר ותראה,
מלבד כל אלמנט הוא רחב בית אחד.
ובדיוק כמו מערך, יש כל אלמנט כתובת.
כל אלמנט של מערך יש מדד, ואנחנו
ניתן להשתמש במדד שיעשה מה שנקרא גישה אקראית במערך.
אנחנו לא צריכים להתחיל ב תחילת המערך,
לחזר דרך כל אלמנט יחיד שלה,
כדי למצוא את מה שאנחנו מחפשים.
אנחנו רק יכולים לומר, אני רוצה להגיע ל אלמנט ה -15 או ה -100 האלמנט.
ואתה יכול פשוט לעבור במספר ש ולקבל את הערך שאתה מחפש.
>> באופן דומה בכל מיקום בזיכרון יש כתובת.
אז אולי הזיכרון שלך נראה משהו כזה.
הנה נתח קטן מאוד של זיכרון, זה 20 בתים של זיכרון.
20 הבתים הראשונים בגללי כתובות שם בתחתית
הם 0, 1, 2, 3, וכך בכל הדרך עד 19.
וכאשר אני מצהיר משתנים ו כאשר אני מתחיל לעבוד איתם,
מערכת הולכת להגדיר בצד קצת מקום לי
בזיכרון כדי שזה יעבוד עם המשתנים שלי.
אז אני יכול להגיד, char ג שווה הון ח ומה הולך לקרות?
ובכן המערכת הולכת להפריש עבורי בית אחד.
במקרה זה בחר מספר הבתים ארבעה, בייט בכתובת ארבע,
וזה הולך לאחסון H מכתב הון שביש לי.
אם אני אומר אז מהירות int מגבלה שווה 65, שזה
הולך להפריש ארבעה בתים של זיכרון בשבילי.
וזה הולך לטיפול אלה ארבעה בתים כיחידה אחת
כי מה שאנחנו עובדים עם הוא מספר שלם כאן.
וזה הולך לאחסון 65 שם.
>> עכשיו אני כבר סוג של אומר לך קצת שקר,
נכון, כי אנחנו יודעים ש מחשבים לעבוד בינארי.
הם לא מבינים בהכרח מה הוא H הון
או מה הוא 65, הם רק מבין בינארי, אפסים ואחדים.
ומה כל כך למעשה אנחנו אחסון שם
אינו האות H והמספר 65, אלא ייצוגי ינארי
כל אלה, אשר נראים משהו קטן כמו זה.
ובפרט ב הקשר של המשתנה השלם,
זה לא הולך רק כדי לירוק אותו ל, זה לא הולך להתייחס אליו כאחד ארבעה
נתח בתים בהכרח, זה באמת קורה
להתייחס אליו כארבעה אחד נתחי בתים, אשר עשוי להיראות משהו כזה.
וגם זה לא לגמרי נכון או,
בגלל משהו שנקרא סדר בתים, שאנחנו לא
הולך להיכנס עכשיו, אבל אם אתה סקרן לגבי,
אתה יכול לקרוא על קטן וסדר בתים גדולים.
אבל למען טענה זו, למען וידאו זה,
בואו פשוט להניח שהוא, ב למעשה, איך מספר 65 הייתם
להיות מיוצג ב זיכרון בכל מערכת,
למרות שזה לא לגמרי נכון.
>> אבל בואו למעשה רק לקבל להיפטר מכל ינארי לחלוטין,
וחושב רק על כH ו -65, זה הרבה יותר קל
לחשוב על זה כמו כי כאדם.
בסדר, אז זה גם נראה אולי המערכת קטנה אקראית שI've-
לא נתן לי בתים 5, 6, 7, ו -8 לאחסון השלם.
יש סיבה לכך, גם, ש אנו לא תקבלו לעכשיו, אבל יספיקו
זה אומר שמה מחשב עושה כאן
כנראה מהלך טוב בחלקו.
לא לתת לי זיכרון זה בהכרח גב אל גב.
למרות שזה הולך לעשות את זה עכשיו אם אני רוצה לקבל מחרוזת אחרת,
בשם משפחה, ואני רוצה לשים לויד שם.
אני הולך צריך להתאים אחד אופי, כל אות של זה
הולך לדרוש אחד דמות, בית אחד של זיכרון.
אז אם אני יכול לשים לויד למערך שלי ככה אני די טוב ללכת, נכון?
מה חסר?
>> זכור כי כל מחרוזת אנחנו עובדים עם בC מסתיים בקו נטוי אפס,
ואנחנו לא יכולים להשמיט את זה כאן, או.
אנחנו צריכים להפריש בית אחד זיכרון להחזיק שכדי ש
יודע מתי המחרוזת שלנו הסתיימה.
אז שוב הסדר זה של הדברים בדרך
מופיע בעצמת זיכרון להיות קצת אקראי,
אבל זה באמת הוא איך רוב המערכות מתוכננות.
בשורה אותם בכפולות ארבעה, מסיבות שוב
כי אנחנו לא צריכים להיכנס עכשיו.
אבל זה, כך די אם נאמר ש לאחר שלוש שורות של קוד אלה,
זה מה שעשוי להיראות כמו זיכרון.
אם אני צריך מיקומי זיכרון 4, 8, ו -12 להחזיק את הנתונים שלי,
זה מה שהזיכרון שלי עשוי להיראות.
>> ופשוט להיות במיוחד קפדן כאן, כאשר
על זיכרון אנחנו מדברים כתובות אנחנו בדרך כלל
לעשות זאת באמצעות סימונים הקסדצימלי.
אז למה אנחנו לא להמיר את כל אלה מעשרוני לסימון הקסדצימלי
רק בגלל שזה בדרך כלל איך אנחנו מתייחסים לזיכרון.
אז במקום להיות 0 ב 19, מה שיש לנו הוא אפס
x אפס אפס דרך x1 שלוש.
אלה הם 20 הבתים של זיכרון ש יש להם או שאנחנו מסתכלים על בתמונה זו
ממש כאן.
>> אז כל מה שנאמר, בואו להתרחק מזיכרון לשנייה
ובחזרה למצביעים.
כאן הוא החשוב ביותר מה שצריך לזכור
כפי שאנו מתחילים לעבוד עם מצביעים.
מצביע הוא דבר יותר מ כתובת.
אני אגיד את זה שוב, כי זה כל כך חשוב,
מצביע הוא דבר יותר מ כתובת.
מצביעים הם כתובות אתרים ל בזיכרון שבו משתנה לחיות.
בידיעה שהוא הופך להיות תקווה קצת יותר קלים לעבוד איתם.
דבר נוסף שאני אוהב לעשות הוא להיות סוג
של התרשימים חזותי המייצג את מה ש קורה עם קווים שונים של קוד.
ואנחנו נעשה את זה כמה פעמים במצביעים,
וכאשר אנחנו מדברים על דינמיים הקצאת זיכרון, כמו גם.
כי אני חושב שדיאגרמות אלה יכול להיות מועיל במיוחד.
>> אז אם אני אומר לדוגמא, k int בקוד שלי, מה קורה?
ובכן מה בעצם קורה הוא אני מקבל זיכרון להפריש עבורי,
אבל אני אפילו לא רוצה אחשוב על זה ככה, אני
רוצה לחשוב על זה כמו קופסא.
יש לי קופסה וזה ירוק בצבע, כי אני
יכול לשים את המספרים השלמים בקופסות ירוקות.
אם זה היה אני דמות אולי יש לי קופסא כחולה.
אבל אני תמיד אומר, אם אני יוצר תיבה שיכול להכיל מספרים שלמים
התיבה שהיא בצבע ירוקה.
ואני לוקח את סמן קבע ואני כותב k בצד שלו.
אז יש לי תיבה שנקראת K, שאליו אני יכול לשים את מספרים שלמים.
לכן, כאשר אני אומר יא int, זה מה שקורה בראש שלי.
אם אני אומר k שווה חמש, מה אני עושה?
ובכן, אני שם את חמש בתיבה, תקין.
זה די פשוט, אם אני אומר יא int, ליצור תיבה שנקראת k.
אם אני אומר k שווה 5, לשים חמש לתוך התיבה.
אני מקווה שזה לא יותר מדי של קפיצה.
הנה שבו דברים הולכים קצת מעניין, אם כי.
אם אני אומר * int PK, גם אפילו אם אני לא יודע מה זה אומר בהכרח,
זה ברור שיש לי משהו לעשות עם שלם.
אז אני הולך לצבוע תיבה זו ירוקה-איש,
אני יודע שיש לו משהו לעשות עם שלם,
אבל זה לא שלם עצמו, כי זה כוכב int.
יש משהו מעט שונה על זה.
כל כך מעורב של מספר שלם, אבל חוץ מזה
לא שונה מדי מ מה אנחנו מדברים.
זה תיבה, שלה יש תווית, זה לובש PK תווית,
וזה מסוגל להחזיק כוכבי int, מה הם אותם.
יש להם משהו לעשות עם מספרים שלמים, ברור.
הנה השורה האחרונה אף.
אם אני אומר PK = & K, וואו, מה בדיוק קרה, נכון?
אז מספר אקראי זה, לכאורה אקראי מספר, מקבל נזרק לתוך התיבה שם.
כל מה שהוא, הוא PK מקבל את הכתובת של k.
אז אני דבקתי בו k מתגורר בזיכרון, הכתובת שלו, את הכתובת של בתיו.
כל מה שאני עושה הוא שאני אומר ערך זה מה שאני הולך
לשים בתוך PK נקרא התיבה שלי.
ומכיוון שהדברים האלה הם מצביעים, וכי מחפשים
במחרוזת כמו אפס x שמונה אפס ג שבע ארבעה שמונה
שני אפס הוא כנראה לא מאוד משמעותי.
כאשר אנחנו בדרך כלל לדמיין מצביעים, אנחנו באמת עושים זאת כמצביעים.
PK נותן לנו המידע אנחנו צריכים למצוא k בזיכרון.
אז בעצם PK יש חץ בזה.
ואם אנחנו הולכים לאורך של חץ ש, לדמיין
זה משהו שאתה יכול ללכת על, אם ללכת לאורכו של החץ,
בקצה קצו של החץ ש, אנחנו יהיה למצוא את המיקום בזיכרון
כאשר k מתגורר.
וזה באמת חשוב כי ברגע שאנחנו יודעים איפה גר k,
אנחנו יכולים להתחיל לעבוד עם הנתונים בתוך שמיקום הזיכרון.
למרות שאנחנו מקבלים קטנטן נשכתי יקדים את המאוחר לעת עתה.
>> אז מה הוא מצביע?
מצביע הוא פריט מידע ש ערך הוא כתובת זיכרון.
זה היה כי אפס x שמונה אפס דברים קורה, שהיה כתובת זיכרון.
זה היה מיקום בזיכרון.
והסוג של מצביע מתאר את הסוג
הנתונים תמצאו ב שכתובת הזיכרון.
אז יש את זכות חלק כוכב int.
אם אני עוקב אחרי חץ זה, זה הולך להוביל אותי למקום.
ומיקום ש, מה ש ימצא שם בדוגמא שלי,
היא תיבה בצבע ירוקה.
זה מספר שלם, זה מה שאני ימצא אם אני הולך לכתובת זו.
סוג נתונים של מצביע מתאר את מה ש
תוכל למצוא שבכתובת הזיכרון.
אז הנה הדבר ממש מגניב אף.
מצביעים יאפשר לנו לעבור משתנים בין פונקציות.
ובעצם להעביר משתנה ולא יעבור עותקים שלהם.
כי אם אנחנו יודעים בדיוק איפה בזיכרון כדי למצוא משתנים,
אנחנו לא צריכים ליצור עותק של זה, אנחנו יכולים פשוט ללכת למקום ש
ולעבוד עם משתנה ש.
אז במצביעי מהות מין של לעשות סביבת מחשב
הרבה יותר כמו בעולם האמיתי, נכון.
>> אז הנה אנלוגיה.
בואו נגיד שיש לי מחברת, נכון, והוא מלא בהערות.
ואני רוצה שתעדכן אותו.
אתה הוא פונקציה ש הערות עדכונים, תקין.
בדרך בה אנו כבר עובד כל כך הרבה, מה ש
קורה הוא שאתה תיקח את המחברת שלי, אתה תלך לעותק החנות,
תוכל לעשות עותק Xerox של כל דף של המחברת.
אתה משאיר את המחברת שלי בחזרה על השולחן שלי כשתסיים,
אתה תלך ולחצות את דברים בי מחברת שאינן מעודכנים או לא נכון,
ואז אתה עובר בחזרה ל שלי הערימה של דפי Xerox
כי הוא העתק מדויק של המחברת שלי עם השינויים שביצעתם אליו.
ובשלב זה, זה תלוי בי כ הפונקציה הקוראת, כמתקשר,
למחליט לקחת את ההערות שלך ו לשלב אותם בחזרה למחשב הנייד שלי.
אז יש הרבה שלבים מעורב כאן, נכון.
כמו האם זה לא יהיה טוב יותר אם אני רק אומר, היי, אתה יכול
לעדכן את המחברת שלי ל שלי, למסור לך את המחברת שלי,
ואתה לוקח את הדברים ו פשוטו כמשמעו לעבור אותם
ולעדכן את הרשימות שלי במחברת שלי.
ולאחר מכן לתת לי את המחברת שלי בחזרה.
זה סוג של מה ש מצביעים יאפשר לנו לעשות,
הם עושים סביבה זו הרבה יותר כמו איך אנחנו פועלים במציאות.
>> בסדר אז זה מה ש מצביע, בואו נדבר
על איך מצביעי העבודה ב- C, ו איך אנחנו יכולים להתחיל לעבוד איתם.
אז יש מצביע פשוט מאוד ב- C נקרא מצביע null.
נקודות מצביע null לשום דבר.
זה כנראה נראה כמו זה בעצם לא דבר שימושי מאוד,
אבל כפי שנראה מעט מאוחר יותר, העובדה
שמצביע null הזה קיים ממש ממש יכול להיות שימושי.
ובכל פעם שאתה יוצר מצביע, ו לא תגדיר-אמצעי הערך שלה
דוגמא של הגדרה מייד הערך שלה
תהיה זוג שקופיות גב שבו אמרתי PK שווה & K,
PK מקבל את כתובתו של k, כ אנחנו תראו מה זה אומר,
אנו רואים כיצד קוד שshortly- אם לא נקבעו הערך שלה למשהו
משמעות מיידית, אתה תמיד צריך
להגדיר את המצביע להצביע על null.
אתה צריך להגדיר את זה כדי להצביע על שום דבר.
>> זה שונה מאוד מ רק עוזב את הערך כפי שהוא
ולאחר מכן הכריז מצביע ורק בהנחה
זה null כי זה רק לעתים נדירות אמיתיים.
אז אתה צריך תמיד להגדיר הערך של מצביע
לnull אם לא יגדיר הערך שלה למשהו משמעותי באופן מיידי.
אתה יכול לבדוק אם הערך של מצביע בטל באמצעות מפעיל השוויון
(==), בדיוק כמוך להשוות כל מספר שלם ערכים או ערכי אופי שימוש (==)
גם כן.
זה סוג מיוחד של קבוע ערך שאתה יכול להשתמש בו כדי לבדוק.
אז זה היה מאוד פשוט מצביע, מצביע null.
דרך נוספת ליצירה מצביע הוא לחלץ
הכתובת של משתנה שכבר יצר,
ואתה עושה את זה באמצעות ו חילוץ כתובת מפעיל.
שכבר ראו בעבר בדוגמא התרשים הראשונה שהראיתי.
אז אם x הוא משתנה שיש לנו כבר יצר של מספר שלם סוג,
אז & x הוא מצביע למספר שלם.
וx היא- זוכר, והוא הולך לחלץ הכתובת של הדבר בצד הימין.
ומאחר שמצביע הוא רק כתובת, מ & x הוא מצביע למספר שלם
ערך שהמקום שבו בחיי x הזיכרון.
זה הכתובת של x.
אז & x הוא הכתובת של x.
בואו ניקח את זה צעד אחד יותר ולהתחבר למשהו
רמזתי בוידאו לפני.
אם עיבוד הוא מערך של זוגות, ואז וסוגר מרובע עיבוד הוא אני מצביע
לכפול.
אוקיי.
ARR הסוגר מרובע אני, אם עיבוד הוא מערך של זוגות,
אז ARR הסוגר מרובע הוא אני אלמנט i-ה ממערך ש,
ו& ARR הסוגר מרובע הוא לי איפה ב זיכרון אלמנט i-ה של עיבוד קיים.
>> אז מה המשמעות כאן?
שם מערכים, המשמעות של כל הדבר הזה,
הוא שהשם של מערך הוא למעשה עצמו מצביע.
אתה כבר עובד עם מצביעים לכל אורך הדרך
בכל פעם שהשתמשת במערך.
זכור מהדוגמא בהיקף משתנה,
לקראת סוף הסרטון אני מציג דוגמא שבה יש לנו פונקציה
int הסט התקשר ו פונקציה שנקראת מערך קבוצה.
והאתגר שלך כדי לקבוע אם לא, או מה
ערכים שאנו הדפסנו סוף הפונקציה,
בסוף התכנית הראשית.
>> אם אתה זוכר מדוגמא ש או אם אתה כבר צפה בסרטון,
אתה יודע שכאשר ך- הקריאה ל int סט ביעילות לא עושה כלום.
אבל השיחה להגדיר מערך עושה.
ואני סוג של לא הקדשתי זמן למה זה היה המקרה באותו הזמן.
אני רק אמרתי, גם זה מערך, זה מיוחד, אתה יודע, יש סיבה.
הסיבה לכך היא שמערך של שם הוא באמת רק מצביע,
ויש את זה מיוחד תחביר הסוגר מרובע ש
לעשות דברים הרבה יותר נחמדים לעבוד איתו.
והם עושים את הרעיון של מצביע הרבה פחות מאיים,
וזו הסיבה שהם סוג הציג בדרך זו.
אבל באמת מערכים הם רק מצביעים.
ולכן כאשר אנו עשה שינוי למערך,
כשעברנו מערך כפרמטר לפונקציה או כטיעון
לפונקציה, את התוכן של המערך למעשה השתנה בשני callee
ובמתקשר.
אשר לכל סוג של אחרים משתנה שראינו לא היה המקרה.
אז זה רק משהו כדי לשמור על ב אכפת כשאתה עובד עם מצביעים,
הוא ששמו של מערך למעשה מצביע
לאלמנט הראשון של מערך זה.
>> אוקי אז עכשיו יש לנו את כל אלה עובדות, בואו נמשיך, נכון.
למה אכפת לנו שבו משהו חי.
ובכן כמו שאמרתי, זה די שימושי לדעת איפה משהו חי
כך שאתה יכול ללכת לשם ולשנות אותו.
לעבוד עם זה ולמעשה יש דבר ש
רוצה לעשות לזה השפעה לקחת משתנה, ולא ייכנס לתוקף בכמה עותק שלו.
זה נקרא ביטול הפניה.
אנחנו הולכים להתייחסות ו נשנינו את הערך שם.
אז אם יש לנו מצביע וזה נקרא מחשב, וזה מצביע על אופי,
אז אנחנו יכולים לומר למחשב PC * ו* הוא שמו של מה שאנחנו תמצאו אם נלך
למחשב הכתובת.
מה שאנחנו תמצאו שם הוא דמות ו * מחשב הוא איך אנחנו מתייחסים לנתונים שב
מיקום.
אז אנחנו יכולים לומר משהו כמו * מחשב = D או משהו כזה,
וזה אומר שכל מה ש היה במחשב כתובת זיכרון,
כל מה שהייתה בעבר הדמות יש, עכשיו הוא D, אם אנחנו אומרים * מחשב = D.
>> אז הנה זה באו שוב עם כמה דברים ג מוזרים, נכון.
אז שראינו * בעבר כ איכשהו חלק מסוג הנתונים,
ועכשיו הוא נמצא בשימוש ב הקשר מעט שונה
כדי לגשת לנתונים במיקום.
אני יודע שזה קצת מבלבל ו זה בעצם חלק מכל זה
כמו, למה יש לי מצביעי מיתולוגיה זו סביבם כמו להיות כל כך מורכב,
הוא סוג של בעיה תחביר, בכנות.
אבל * משמש בשני ההקשרים, הן כחלק משמו של הסוג,
ואנו רואים מעט משהו מאוחר יותר אחר, גם.
ועכשיו הוא מפעיל dereference.
אז זה הולך להתייחסות, זה ניגש לנתונים
במיקום של המצביע, ו מאפשר לך לשנות אותו כרצונו.
>> עכשיו זה דומה מאוד ל ביקור השכן שלך, נכון.
אם אתה יודע מה שלך השכן מתגורר, אתה
לא להסתובב עם השכן שלך.
אתה יודע שאתה יקרה ל יודע איפה הם גרים,
אבל זה לא אומר שעל ידי כוח שיש ידיעה ש
אתה נמצא באינטראקציה איתם.
אם אתה רוצה לתקשר איתם, אתה צריך ללכת לבית שלהם,
אתה צריך ללכת למקום שבו הם חיים.
וברגע שאתה עושה את זה, אז אתה יכול לקיים אינטראקציה
עם אותם בדיוק כמו שהיית רוצה.
ובאופן דומה עם משתנים, אתה צריך ללכת לכתובת שלהם
אם אתה רוצה לתקשר אותם, אתה לא יכול פשוט יודע את הכתובת.
והדרך שאתה הולך לכתובת היא לשימוש *, מפעיל dereference.
מה אתה חושב שקורה אם ננסה וdereference
מצביע שערכו הוא null?
נזכיר כי null המצביע מצביע על שום דבר.
אז אם אתה מנסה וdereference שום דבר או ללכת לשום כתובת,
מה אתה חושב שקורה?
פילוח גם אם ניחשת אשמה, אתה רוצה להיות צודק.
אם תנסה וdereference מצביע null,
אתה סובל פילוח דופי. אבל חכה,
לא אני אומר לך, ש אם אתה לא הולך
כדי להגדיר הערך שלך שלך מצביע למשהו משמעותי,
אתה צריך להגדיר לnull?
אני עשיתי ולמעשה הפילוח אשמה היא סוג של התנהגות טובה.
>> האם אי פעם הכריז על משתנה ו לא הוקצה הערך שלה באופן מיידי?
אז אתה פשוט אומר int x; אתה לא למעשה להקצות אותו לשום דבר
ואז בשלב מאוחר יותר בקוד שלך, אתה מדפיס את הערך של x,
יש עדיין לא שהוקצה אותו לשום דבר.
לעתים קרובות תקבל אפס, אבל לפעמים אתה
אולי תקבל קצת מספרים אקראיים, ו אין לך מושג מהאיפה זה בא.
כמו כן יכול דברים יקרה עם מצביעים.
כאשר אתה מצהיר על מצביע int * PK למשל,
ואתה לא להקצות אותו ערך, אתה מקבל ארבעה בתים לזיכרון.
לא משנה מה ארבעה בתים של יכול זיכרון המערכת
למצוא, כי יש כמה ערך משמעותי.
ואולי היה משהו כבר שם ש
הוא כבר לא היה צריך על ידי אחר פונקציה, כל כך פשוט שיש לך
כל הנתונים היה שם.
>> מה אם אתה ניסית לעשות dereference כמה כתובת שלא- היו
כבר בתים ומידע ב שם, זה עכשיו במצביע שלך.
אם תנסה וdereference מצביע ש, ייתכן שאתה מתעסק עם כמה זיכרון
שלא התכוון להתעסק עם כל זה.
ולמעשה אתה יכול לעשות משהו ממש הרסני,
כמו לשבור תכנית אחרת, או לשבור את פונקציה אחרת,
או לעשות משהו זדוני ש אתה לא מתכוון לעשות בכל.
ואז זה למה זה למעשה רעיון טוב
להגדיר מצביעים שלך לnull אם אתה לא להגדיר אותם למשהו משמעותי.
זה כנראה טוב יותר ב סופו של היום לתכנית שלך
לקרוס אז לזה לעשות משהו שמפשל
תכנית אחרת או פונקציה אחרת.
התנהגות זו כנראה גם פחות אידיאלי מאשר רק מתרסק.
ואז זה למה זה למעשה הרגל טוב
להיכנס להגדרת המצביעים שלך לnull אם אתה לא להגדיר אותם
לערך משמעותי מייד, ערך שאתה יודע
ושאתה יכול בבטחה dereference.
>> אז בואו נחזור עכשיו ותסתכל בתחביר הכולל של המצב.
אם אני אומר int p * ;, מה יש לי רק לעשות?
מה שעשיתי הוא זה.
אני יודע את הערך של p הוא כתובת כי כל המצביעים הם רק
כתובות.
אני יכול p dereference באמצעות המפעיל *.
בהקשר זה כאן, ממש ב עליון זוכר * הוא חלק מהסוג.
Int * הוא סוג נתונים.
אבל אני יכול dereference p באמצעות המפעיל *,
ואם אני עושה זאת, אם אני הולך לכתובת זו, מה אני תמצא בכתובת ש?
אני תמצא את מספר שלם.
אז * int p הוא בעצם אומר, עמ 'הוא כתובת.
אני יכול dereference p ואם אני עושה, אני תמצא את מספר שלם
באותו מיקום בזיכרון.
>> אישור אז אמרתי היה עוד דבר מעצבן עם כוכבים
וכאן המקום שבו ש דבר מעצבן עם כוכבים הוא.
האם אי פעם ניסינו להכריז משתנים מרובים מאותו הסוג
על אותו הקו של קוד?
אז לרגע, להעמיד פנים שהשורה, הקוד אני באמת צריך שם בירוק
הוא לא שם וזה רק אומר x int, y, z ;.
מה שהיה עושה הוא בעצם ליצור שלושה משתנים שלמים בשבילך,
אחד x נקרא, אחד בשם y, ואחד בשם Z.
זוהי דרך לעשות את זה בלי יש לפצל על שלושה קווים.
>> כאן המקום לקבל כוכבים מעצבן שוב אם כי,
כי * הוא למעשה חלק שני שם הסוג והחלק
של השם המשתנה.
ולכן אם אני אומר * int px, py, PZ, מה ש למעשה מקבלים הוא מצביע למספר שלם
נקרא px ושני מספרים שלמים, py וPZ.
וזה כנראה לא מה ש אנחנו רוצים, זה לא טוב.
>> אז אם אני רוצה ליצור מצביעים מרובים על אותו הקו, מאותו הסוג,
וכוכבים, מה שבאמת צריך לעשות הוא לומר * int הרשות הפלסטינית, * PB, * מחשב.
עכשיו שרק אמר ש ואומר לך את זה עכשיו,
אתה כנראה לא תעשה את זה.
וזה כנראה דבר טוב באמת, כי בטעות אתה עלול
להשמיט כוכב, משהו כזה.
זה כנראה הכי טוב אולי להכריז מצביעים על קווים בודדים,
אבל זה רק עוד אחד תחביר המעצבן
דברים עם כוכבים שמרכיבים מצביעים כל כך קשה לעבוד איתו.
כי זה פשוט תחבירי זה בלגן אתה צריך לעבוד דרך.
בעזרת תרגול שהיא עושה באמת יהפוך לטבע שני.
אני עדיין עושה טעויות עם זה עדיין לאחר תכנות במשך 10 שנים,
אז אל תכעס אם קורה משהו לך, שזה די נפוץ בכנות.
זה באמת סוג של פגם של התחביר.
>> אישור אז אני סוג של הבטחתי שהיינו לבקר
המושג עד כמה גדול הוא מחרוזת.
ובכן, אם אמרתי לך ש מחרוזת, יש לנו באמת סוג של
משקר לך כל הזמן.
אין סוג נתונים הנקראים מחרוזת, ולמעשה אני
הזכיר את זה באחד משלנו קטעי וידאו מוקדמים על סוגי נתונים,
המחרוזת שהייתה סוג הנתונים ש נוצר עבורך בCS50.h.
אתה צריך include # CS50.h כדי להשתמש בו.
>> ובכן המחרוזת היא באמת רק כינוי למשהו
נקרא char *, מצביע לאופי.
ובכן מצביעים, כזכור, רק מטפל.
אז מה הוא הגודל בבתים של מחרוזת?
ובכן זה ארבעה או שמונה.
והסיבה שאני אומר ארבעה או שמונה הוא משום שהיא למעשה
תלוי במערכת, אם אתה משתמש ב IDE CS50, char * הוא בגודל של char
* הוא שמונה, זה מערכת של 64 סיביות.
כל כתובת בזיכרון היא ארוכה 64 סיביות.
אם אתה משתמש במכשיר CS50 או באמצעות כל מחשב 32 סיביות,
ושמעת שטווח של 32 סיביות מכונה, מה היא מכונה 32 ביט?
ובכן זה רק אומר שכל כתובת בזיכרון היא ארוכה 32 סיביות.
וכך 32 סיביות הוא ארבעה בתים.
אז * char הוא ארבעה או שמונה ביטים בהתאם למערכת שלך.
ואכן כל סוגי הנתונים, ומצביע לכל נתוני
הקלד, שכן כל המצביעים הם רק כתובות, ארבעה או שמונה בתים.
אז בואו לבקר זה התרשים ובואו נסיים
בסרטון זה עם קצת פעילות גופנית כאן.
אז הנה התרשים שעזבנו את עם בתחילת הווידאו מאוד.
אז מה קורה עכשיו אם אני אומר * PK = 35?
אז מה זה אומר כשאני אומר, * PK = 35?
קח שני.
* PK.
בהקשר כאן, * הוא מפעיל dereference.
לכן, כאשר dereference משמש מפעיל,
אנחנו הולכים לכתובת הצביעה על ידי PK, ואנחנו נשנה את מה שאנו מוצאים.
אז * PK = 35 ביעילות עושה את זה לתמונה.
אז זה בעצם מבחינה תחבירית זהה לשל שאמר k = 35.
>> עוד אחד.
אם אני אומר מ 'int, אני יוצר משתנה חדש בשם מ '.
תיבה חדשה, זה קופסא ירוקה כי זה הולך להחזיק מספר שלם,
וזה שכותרתו מ '.
אם אני אומר מ '= 4, שמתי מספר שלם לתוך התיבה ש.
אם נניח PK = & M, איך עושה שינוי תרשים זה?
PK = & M, אתה זוכר מה ומפעיל עושה או נקרא?
זכור כי וכמה שם משתנה הוא הכתובת של שם משתנה.
אז מה שאנחנו אומרים הוא PK מקבל את הכתובת של מטר.
וכך ביעילות מה שקורה תרשים הוא שPK נקודות כבר לא
לk, אבל נקודות למ '.
>> שוב מצביעים מאוד מסובך לעבוד עם
והם לוקחים הרבה בפועל, אלא משום ש
היכולת שלהם כדי לאפשר לך להעביר נתונים בין פונקציות
ובעצם יש לי אלה שינויים ייכנסו לתוקף,
מקבל את הראש סביב באמת חשוב.
זה כנראה המסובך ביותר נושא שאנו דנים בCS50,
אבל זה הערך ש תקבל משימוש במצביעים
עולה בהרבה על הסיבוכים שמגיע מלימודם.
אז אני מאחל לך את הטוב שב מזל ללמוד על מצביעים.
אני דאג לויד, זה CS50.