Pass By Value
תמונת הזכרון
בשביל להבין מה הבעיה שאנחנו מנסים לפתור בכלל, נסתכל על הדוגמא הבאה:
#include <stdio.h>
void swap(int a, int b) {
int tmp = a;
a = b;
b = tmp;
}
int main() {
int a = 1;
int b = 5;
printf("before call to swap: a = %d, b = %d", a, b);
swap(a, b);
printf("after call to swap: a = %d, b = %d", a, b);
}
לכאורה מדובר על פונקציה פשוטה - מקבלת שני int-ים ומחליפה ביניהם. עם זאת, כשנריץ את התוכנית, נקבל פעמיים את אותה ההדפסה. קחו דקה או שתיים לנסות לחשוב למה.
העברת ארגומנטים לפונקציות ומחסנית הקריאות
הסיבה שהקריאה לפונקציה swap לא החליפה את הערכים של הארגומנטים שלנו נוגעת ישירות לצורה שבה קריאה לפונקציה מתבצעת. נזכיר את השלבים כפי שלמדנו בפרק הקודם:
-
לפני הקריאה לפונקציה
swap, הקומפיילר מייצר פקודות לבניית ה-stack frame שלה - ספציפית, הוא מעתיק את הארגומנטיםaו-bמהפונקציהmainלתוך ה-stack frame החדש. -
לפני תחילת ריצת הפונקציה
swap, האיבר העליון ביותר בזכרון במחסנית הקריאות מכיל את המשתניםaו-bשל הפונקציהswap. מתחתיו בזכרון במחסנית הקריאות נמצא ה-stack frame של הפונקציהmain, בו נמצאים במקום אחר לגמרי המשתניםaו-bשל הפונקציהmain. -
בסיום הפונקציה
swap, הקומפיילר מייצר פקודות לקיפול מחסנית הקריאות וחזרה ל-stack frame של הפונקציהmain. המשתניםaו-bשבאותו ה-stack frame לא השתנו בכלל!
כלומר, בדיעבד אחרי שאנחנו מבינים קצת יותר איך מתבצעת בפועל קריאה לפונקציה, לא מפתיע שהמשתנים ב-main לא משתנים - הפונקציה swap קיבלה עותק של המשתנים ולא את המשתנים עצמם. בפועל, a ו-b שהגדרנו ב-main נמצאים בכתובת שונה לחלוטין בזכרון מהעותקים שלהם שעוברים לפונקציה.
הסיבה לכך, כפי שראינו בעבר, היא שבשפת C ארגומנטים עוברים לפונקציות ע״י הערך שלהם בלבד. מנגנון זה נקרא pass by value - מיד נראה דרך נוספת להעביר ארגומנטים לפונקציה שתאפשר לנו לבצע את המשימה שרצינו.