C++/מצביעים והמשתנה הפניה

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי
< C++
קפיצה לניווט קפיצה לחיפוש

מהו מצביע?[עריכה]

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

int *num = reinterpret_cast<int *>(7);

גם המרה בסגנון הישן תעבוד:

int *num = (int *)7;

בשני המקרים הנ"ל, אנו מגדירים מצביע מסוג int (כלומר, הוא מצביע לשטח בזיכרון בגודל של int). מצביע זה מצביע על הכתובת 7 בזיכרון.

אמנם בשפת C אפשר להציב ערך שלם ישירות לתוך מצביע, אך ב-++C נדרשת המרה מפורשת על מנת לאפשר הצבה כזו. יוצא מן הכלל הוא הצבת מספר 0 - עבור תאימות לאחור עם מצביע "אפס" הישן - NULL. NULL משמש לאיפוס מצביעים ומוגדר בפועל כמספר שלם 0. לפי התקן המעודכן של ++C משתמשים במילה שמורה nullptr לאיפוס מצביעים:

int *num = 0; // הגדרת מצביע למספר שלם עם הצבה מפורשת של 0
int *num = NULL; // הגדרת מצביע למספר שלם עם הצבת מצביע "אפס" בסגנון הישן
int *num = nullptr; // C++ הגדרת מצביע למספר שלם עם הצבת מצביע "אפס" לפי התקן המעודכן של

להלן דוגמה להגדרת מצביע המצביע לכתובת של משתנה אחר:

char c = 'A';
char *p = &c;

גישה למשתנה תתצבע באמצעות הוספת כוכבית (*) לפני שם המצביע. לדוגמה, בהמשך לדוגמת הקוד הקודמת נוכל לשנות את תוכנו של המצביע באמצעות:

*p = 'B';

מהו משתנה הפניה?[עריכה]

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

יישום בדוגמה פשוטה[עריכה]

הבה נגדיר משתנה הפניה:

int num;
int &ref = num;

למשתנה הפניה קראנו ref, הכרזנו אותו כמפנה לטיפוס int, והקדמנו לשמו את התו &. בדומה למקרה של הכרזת מצביע, שם נקדים את התו *.
הפננו את המשתנה ref למשתנה num. שימו לב: לא התרחשה כאן השמת ערכים, אלא הפניה של המשתנה ref למשתנה num, כזו הפניה אגב, יכולה להתרחש רק פעם אחת בחייו של משתנה הפניה, וחייב להתבצע בהכרזה שלו. עכשיו אם נשנה את ערכו של ref, ישתנה גם ערכו של num, וכך גם ההפך:

ref = 10;
cout << num; //10
num = 20;
cout << ref; //20

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

שימוש בפונקציות[עריכה]

כמו שאמרנו קודם, השימוש העיקרי של משתני הפניה, כמו של מצביעים, הוא בפונקציות. לדוגמה, נכתוב פונקציה שמחליפה בין ערכיהם של שני משתנים בשם ()swap:

#include<iostream.h>

void swap(int &a, int &b);

int main() {
   int num1 = 5, num2 = 10;
   swap(num1, num2);
   cout << num1 << endl << num2;
   return 0;
}

void swap(int &a,int &b) {
   int temp;
   temp = a;
   a = b;
   b = temp;
}

שימו לב שהפרמטרים המועברים לפונקציה, הם ללא שום אופרטור מצביע.
ובכל זאת הפונקציה משפיעה על המשתנים num1 ו-num2 שנמצאים בתוכנית.
בתוך הפונקציה, הגישה לפרמטרים a ו-b היא שגרתית כאילו הם משתנים רגילים, לאחר שכל אחד מהם כבר מופנה למשתנה שנשלח לו בארגומנט, בהתאמה.
הפונקציה כמובן אינה מחזירה כלום ולכן מוגדרת כ-void.

משתני הפניה כערכים מוחזרים[עריכה]

ניתן לייצור משתנה הפניה, שיוחזר מפונקציה (כאן num הוא משתנה גלובלי כלשהו):

int &getnum() {
   int &ref = num;
   return ref;
}

הטיפוס המוחזר של הפונקציה ()getnum הוא ערך של int בהפניה. אפשר להשתמש בפונקציה בכדי לקבל את ערכו של num כך:

cout << getnum();

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

getnum() = 50;

עכשיו ערכו של num הוא 50.


- מצביעים והמשתנה הפניה -