PracticU

העברת פרמטרים לפונקציה - by ref

בלי כתוביותעם כתוביות
PracticU › קורס יסודות התכנות - שפת C# .NET - קורס תכנות למתחילים - דוט-נט / סי-שארפ - חומר לימוד של מדעי המחשב › העברת פרמטרים לפונקציה - by ref
מילון מושגים:
פרמטר - ערך שמועבר לפונקציה או לפקודה כקלט, ומשפיע על אופן פעולתן ועל התוצאה שהן מחזירות.
פונקציה - קטע קוד בעל שם שמבצע משימה מוגדרת, מקבל ערכי קלט (פרמטרים) ויכול להחזיר תוצאה. מאפשרת לארגן קוד ולהשתמש בו שוב.
משתנה - שם שמפנה למקום בזיכרון שבו נשמר ערך שיכול להשתנות במהלך ריצת התוכנית, כמו מספר, טקסט או אובייקט.
זיכרון - רכיב מהיר ונדיף שבו המחשב שומר נתונים ותוכניות בזמן ריצתם. תוכנו נמחק עם כיבוי המחשב.
מתודה - פונקציה המוגדרת בתוך מחלקה ומתארת פעולה שאובייקטים מאותה מחלקה יכולים לבצע.

העברת פרמטרים לפונקציה - by ref
הסרטון מסביר איך פונקציה יכולה לשנות משתנה שנשלח אליה, באמצעות המילים ref ו-out, ומה ההבדל ביניהן.
שליחה רגילה מעתיקה את הערך
כשמשתנה מסוג int נשלח לפונקציה, התוכן שלו מועתק לעותק נפרד. בדוגמה הפונקציה init משנה את העותק ל-100, והמשתנה המקורי נשאר 10. ההדפסה לפני הקריאה, בתוך הפונקציה ואחריה מציגה 10, 100 ו-10.
ref - התייחסות למשתנה המקורי
1. שליחה והגדרה: גם בהגדרת הפונקציה וגם בקריאה כותבים ref. הפרמטר בפונקציה הוא כינוי למשתנה המקורי, ולכן שינוי בתוך הפונקציה משנה את המשתנה המקורי.
2. יעילות: לטיפוסים גדולים, למשל DateTime, שולחים רק את הכתובת בזיכרון, כארבעה בתים, במקום להעתיק את כל הערך. זה מהיר יותר וחוסך זיכרון.
3. תנאי: לפני השליחה חובה שלמשתנה יהיה ערך. אחרת מופיעה השגיאה "use of unassigned local variable".
out - אתחול מתוך הפונקציה
1. חובת אתחול: פונקציה עם פרמטר out חייבת להכניס לו ערך לפני שהיא מסיימת. אחרת מופיעה השגיאה "out parameter must be assigned before control leaves the current method".
2. אין צורך בערך קודם: המשתנה שנשלח ל-out לא חייב להיות מאותחל לפני הקריאה, ואי אפשר להשתמש בו בתוך הפונקציה לפני שהכניסו לו ערך.
3. דוגמה: הפונקציה GetTwoNumbersFromUser מבקשת מהמשתמש שני מספרים ומכניסה אותם לפרמטרי out. אחרי הקריאה למשתנים a ו-b יש את הערכים שהמשתמש הכניס, ולא אפסים.
שימו לב
ref מתאים לשינוי ערך קיים, ו-out מתאים לאתחול ערכים מתוך הפונקציה. ההבדל הראשון: ref דורש ערך מראש, out לא. ההבדל השני: out מחייב אתחול בתוך הפונקציה, ו-ref לא.
השיעור הבא בקורס: פונקציות - Functions (הסבר נוסף)

פרקי ההרצאה: העברת פרמטרים לפונקציה - by ref

  1. 00:00

    פונקציה שלא משנה את המשתנה המקורי

  2. 01:32

    העתקת הערך לעותק נפרד בפונקציה

  3. 03:35

    ref: התייחסות למשתנה המקורי

  4. 04:59

    הפרמטר כינוי למשתנה המקורי

  5. 07:10

    למה ref חוסך זיכרון בטיפוסים גדולים

  6. 09:40

    דוגמה: פונקציה שמדפיסה תאריך

  7. 12:03

    DateTime גדול מאינטג'ר: השוואת גודל

  8. 13:57

    מעבר לנושא out

תמלול ההרצאה: העברת פרמטרים לפונקציה - by ref

הטקסט המלא של הדקות הראשונות בהרצאה «העברת פרמטרים לפונקציה - by ref» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.

  1. 00:01

    אנחנו עדיין בפונקציות ואנחנו הולכים לראות משהו מאוד מעניין שנקרא out the ref parameters אבל לפני זה בואו נסתכל על איזושהי התנהגות מסוימת שקיימת כאשר אנחנו קוראים לפונקציה ושולחים משתנה בואו נניח שיש לנו פה פונקציה שנקראת init היא לא מחזירה לנו שום דבר ולכן אנחנו רואים void בערך המוחזר והיא מקבלת איזשהו integer num

  2. 00:32

    ומה שהפונקציה הזאת עושה זה מכניסה בתוך num את המספר mer כעת אנחנו נמצאים במיין, אנחנו מגדירים x ואנחנו מכניסים בתוך x את המספר 10. בואו נקרא לפונקציה ונשלח לה את x, נדפיס את x אחרי הפונקציה, אחרי הקריאה ולפני הקריאה.

  3. 01:01

    אז בואו נחשוב רגע מה הולך להיות מודפס. אז כמובן שכאן אנחנו רואים שהולך להיות מודפס 10, הפונקציה מקבלת את הx בעצם, את המספר, מאתחלת אותו ב-100 ואז אנחנו מדפיסים.

  4. 01:19

    השאלה היא האם יודפס לנו 100 כפי שהפונקציה התחילה אותו או שיודפס לנו 10 או שיודפס משהו אחר. אז התשובה היא שהולך להיות מודפס 10 והסיבה היא שכאשר אנחנו שולחים משתנה לדוגמה אינטג'ר לפונקציה אז מה שהמערכת עושה היא לוקחת את התוכן של המשתנה כלומר 10

  5. 01:42

    ומעתיקה אותו לעותק נפרד שנמצא במשתנה שהפונקציה מקבלת. זאת אומרת שכביכול יש לנו פה שני משתנים, יש לנו x שמכיל 10 ויש לנו num שהוא משתנה נפרד שמוכר רק בגבולות הפונקציה אינית ושקיבל את הערך 10 ולכן ישנם שני משתנים, בעצם יש עותק של המשתנה המקורי בפונקציה.

  6. 02:12

    הפונקציה עובדת רק על העותק, כלומר רק על המשתנה שהיא מכירה וזה כמובן לא אותו משתנה שקיים במיין. אז היא משנה את המשתנה הזה ל-100 ואכן הוא השתנה ל-100.

  7. 02:25

    אם אנחנו נבצע כאן הצגה של נ"מ וכאן הצגה של נ"מ אנחנו נראה שבהצגה הראשונה יוצג לנו 100, ביתר דיוק 10 מפני שעדיין לא שינינו אותו, ובהצגה השנייה כמובן יוצג לנו 100. זאת אומרת כאן יוצג 10 לאחר מכן אנחנו שולחים אותו לפונקציה פה יוצג עוד 10 זה ה-10 השני שיוצג.

  8. 02:54

    הפונקציה משנה את העותק ל-100 יוצג 100 ולאחר מכן אנחנו חוזרים אבל לא נגענו במשתנה המקורי שנקרא x ולכן ערכו לא שונה ויכיל 10. זאת אומרת שאנחנו נראה פעמיים 10 על המסך לאחר מכן 100 ולאחר מכן שוב 10. בואו נריץ וזה בדיוק מה שאנחנו מקבלים. אוקיי אז אנחנו בעצם רואים את ההתנהגות

  9. 03:22

    הזאת בגלל שהיה פה העתקה של תוכן המשתנה למשתנה אחר נפרד לגמרי. עכשיו, מה אנחנו הולכים לראות? אנחנו הולכים לראות שתי מילים, אחת נקראת רף והשנייה נקראת אאוט.

  10. 03:42

    נתחיל עם רף. רף אומרת דבר כזה: אנחנו יכולים לשלוח את המשתנה כאשר הפונקציה מקבלת רף אינט נאם. שימו לב שעכשיו הקריאה לפונקציה אומרת שאנחנו צריכים גם כאן לרשום את המילה רף.

  11. 04:03

    רף זה קיצור של רפרנס, כלומר התייחסות ל... ומה שבעצם קורה כאן זה שהפונקציה מתייחסת על ידי המשתנה num למשתנה המקורי ל-x. ולכן מה שקרה כאן זה אפשר לחשוב שהמערכת לוקחת את המשתנה num ובעצם לא פותחת משתנה חדש אלא מתייחסת למשתנה המקורי x.

  12. 04:33

    אפשר להגיד שכעת במיין יש לנו משתנה x, בפונקציה יש לנו משתנה שנקרא num, מכיר x הפונקציה מכירה num אבל num זה כינוי למשתנה המקורי x ולכן שניהם מדברים על אותו תא זיכרון אז אם הפונקציה משנה את num זה כאילו שהיא שינתה את המשתנה המקורי x אז מה אנחנו בעצם הולכים לראות עכשיו אנחנו הולכים לראות כאן הצגה של 10 לאחר מכן

  13. 05:11

    אנחנו שולחים את ההתייחסות ל-x לפונקציה num ו-x הולכים להיות אותו המשתנה בול שהוא בעצם x כאן אנחנו הולכים עדיין להדפיס 10 כי לא שינינו אותו הפונקציה הולכת להכניס 100 בתוך num אבל זה בעצם הכנסת 100 בתוך x כי הם בדיוק אותו משתנה num מתייחס ל-x זה הקונספט של רפרנס נתייחס ל-x ואז אנחנו הולכים כמובן פה לראות 100 אבל הדבר החשוב הוא שגם

  14. 05:47

    כאן אנחנו הולכים לראות 100. בואו נריץ את זה. ואנחנו רואים שהפונקציה הצליחה לשנות את המשתנה המקורי. ה-100 האחרון שאתם רואים כאן זה בעצם המשתנה המקורי שהוא x, והפונקציה התייחסה אליו והצליחה לשנות אותו.

  15. 06:08

    אז רף זה בעצם שיטה שבה אנחנו יכולים לשנות את המשתנים שנשלחים לפונקציה על ידי הפונקציה. אז בעצם אין פה עותק נפרד, אלא יש פה רק משתנה אחד ויחיד והפונקציה מתייחסת אליו אפילו שאין לה כביכול גישה אליו.

  16. 06:26

    תפימו לב שמהמיין אני לא יכול להגיע לנאם, המיין לא מכיר את נאם. מהפונקציה אני לא יכול להגיע ל-x, הפונקציה לא מכירה את x. הפונקציה מכירה רק את המשתנה נאם, המיין מכיר רק את המשתנה x, אבל הם אותו משתנה בדיוק, פשוט השמות שלהם שונים בין המיין לבין הפונקציה.

  17. 06:51

    עכשיו, למה זה בדיוק נועד? למה על הפונקציה לשנות את המשתנה המקורי? אז למעשה אנחנו צריכים להבין שהמשמעות של רף זה לא בדיוק לשנות את המשתנה המקורי. המשמעות של רף זה שאנחנו לא נצטרך לשלוח לפונקציה עותק של כל המשתנה.

  18. 07:16

    עכשיו אינטג'ר זה משתנה בגודל ארבעה בתים בזיכרון, זאת אומרת שהוא נחשב מאוד מאוד קטן. אבל בואו תארו לעצמכם אם היה לי פה משתנה בגודל אחר, שהוא לא היה אינטג'ר איזה משתנה יש לנו שהוא מאוד מאוד מאוד גדול אז למעשה במשתנים הפרימיטיביים שאנחנו למדנו בקורס הזה אין משתנים שהם מאוד מאוד גדולים אבל זה לא אומר שלא ניתן לבנות

  19. 07:45

    טיפוסים נוספים שהם בוא נגיד user defined types שהמשתמש או המתכנת יותר נכון יכול לבנות שהם בנויים מהמון טיפוסים פרימיטיביים אז בוא נניח שאתם בונים איזשהו טיפוס חדש שבנוי מהמון המון טיפוסים פרימיטיביים.

  20. 08:06

    ואתם רוצים עכשיו לשלוח אותו לפונקציה, בוא נניח לצורך הצגה. עכשיו, במודול הזה אנחנו לא לומדים איך ליצור טיפוסים חדשים.

  21. 08:14

    זה הולך להיות במודול הבא שנקרא Object Oriented Programming, תכנות מונחה עצמים ששם אנחנו בונים עצמים חדשים משלנו.

  22. 08:24

    אבל בוא נניח שבניתם איזשהו טיפוס מאוד מאוד גדול ואתם רוצים עכשיו לשלוח אותו לפונקציה. אם הייתם שולחים אותו בשיטה הסטנדרטית, בעצם מה שהיה קורה זה שהתוכנית הייתה מעתיקה כל התוכן שלו לעותק נפרד ואם התוכנית הייתה מעתיקה אותו לעותק נפרד זה היה פשוט מבזבז גם מקום בזיכרון וגם לוקח זמן אם אנחנו שולחים אותו ברף זה אומר שאנחנו

  23. 08:54

    שולחים רק את הכתובת בזיכרון שלו הכתובת בזיכרון שלו גודלה יחסית קטן בערך ארבעה בתים אז השליחה ברף עבור משתנים מאוד גדולים היא הרבה יותר מהירה בזיכרון, או יותר נכון מהירה מבחינת זמן ריצה וחוסכת בזיכרון, מאשר אם אנחנו שולחים בלי רף ואז כל המשתנה

  24. 09:18

    מועתק. כמובן שאם אנחנו שולחים אינטג'ר אין לזה שום משמעות, כי גם גודל אינטג'ר זה ארבעה בתים וגם הגודל של הכתובת זה ארבעה בתים.

  25. 09:29

    אז בואו נחזיר את רף ומה שהיינו יכולים לראות לצורך הדוגמה זה כזה דבר. בואו נניח שהייתה לנו פה פונקציה static void והפונקציה הזאת הייתה נקראת printDate והיא הייתה מקבלת משתנה שנקרא DateTime ומה שהיא הייתה עושה היא פשוט הייתה מתחילה להציג

  26. 09:59

    DateTime.Ear משורשר עם DateTime.Month משורשר עם או אפילו בוא נעשה את זה בתצוגה של ישראל day time נקודה day, month year משורשר עם day time נקודה hour, day time minutes משורשר עם day time seconds משורשר עם נקודה ואז day time milliseconds.

  27. 11:17

    זאת אומרת שאנחנו רואים כאן, בואו נבצע איזושהי הפרדה, אנחנו רואים כאן שמשתנה day time הוא כבר משתנה יחסית מאוד גדול, מאוד אבל יחסית גדול יותר מאינטג'ר כי הוא מחזיק בתוכו המון תתי משתנים כל אחד מהם הוא אינטג'ר בפני עצמו אז תחשבו מה הגודל של daytime אומרים שיש לנו 1, 2, 3, 4, 5, 6, 7 משתנים מטיפוס אינטג'ר זאת אומרת שהוא

  28. 11:49

    פי 7 יותר גדול מאינטג'ר ובינינו יש בתוכו עוד הרבה דברים אחרים אז למרות שהוא לא נחשב באמת גדול הוא עדיין יותר גדול מאינטג'ר עכשיו אם בוא נניח שהייתה לנו בתוכנית איזשהו משתנה מטיפוס דייט טיים נקרא לו מיי דייט טיים ונחניף בתוכו now now זה אומר הזמן הנוכחי שניקח מהמחשב ועכשיו היינו רוצים להדפיס פרינט

  29. 12:29

    דייט ולשלוח את מיי דייט טיים בואו נחשוב רגע מה בעצם קורה כאן מה שקורה כאן זה שהמשתנה עצמו מועתק לעותק נפרד לפונקציה וההעתקה הזאת לוקחת כמובן מקום בזיכרון מפני שזה עכשיו שני עותקים נפרדים ולוקחת זמן כי העתקה תמיד לוקחת זמן אבל זה כמובן עובד.

  30. 12:58

    בואו נריץ ונראה שיש לנו פה ממש את התאריך הנוכחי והשעה הנוכחית. בסדר, אז אם היינו אומרים שאנחנו רוצים לקבל רף של דיי טיים, המהירות של השליכה לפונקציה הייתה הרבה יותר מהירה מפני שעכשיו אנחנו לא שולחים את כל העותק של המשתנה ומשכפלים אותו

  31. 13:24

    אלא שולחים אך ורק את כתובת המשתנה שזה סך הכל ארבעה בתים ולכן המהירות הזאת הייתה הרבה יותר גדולה. עכשיו כמובן שאנחנו לא רואים כאן שום הבדל כי מדובר פה במהירויות מאוד מאוד גבוהות אבל תחשבו מה היה קורה אם היה לנו המון מקומות בתוכנית שהיינו רוצים לרוץ ולבצע הדפסות או שליחות לפונקציה של המון המון משתנים מטיפוס דיי טיים.

  32. 13:49

    זה בעצם מייעל לנו את הריצה, מייעל לנו את השליחה לפונקציה, את המהירות, וכמובן את הבזבוז זיכרון שיש לנו בפונקציות עצמן.

  33. 14:02

    זה המטרה של רף. בואו נעבור ונראה מה המטרה של אאוט. נחזור בחזרה לכאן,

לקורס המלא: קורס C# למתחילים אונליין

ההרצאה הקודמת: פונקציות - Functions (חלק 2)

ההרצאה הבאה: פונקציות - Functions (הסבר נוסף)

הרצאות קשורות מקורסים אחרים

  • מצביע לפונקציה - Delegate
  • פונקציה Scalar - עם פרמטרים
  • שמות פרמטרים של פעולות
  • העברת קבצים עם WinScp

קורסים נוספים במסלול

  • קורס פיתוח משחקים יוניטי - Unity - שפת #C