پوینتر و رفرنس تو برنامه نویسی به ظاهر پیچیده میان و اگه قضیه پشتشون رو ندونی حسابی گیجت میکنن
ولی اگه بری ببینی قضیه چیه میفهمی منطق خیلی ساده ای دارن و به راحتی میشه باهاشون کار کرد
پس بریم یک بار برای همیشه قضیه رو جمع کنیم!
کل این قضیه پوینتر و رفرنس داره حول محور رم میچرخه پس بیاید اول یکم از اینکه رم اون پشت داره چیکار میکنه صحبت کنیم
بصورت ساده میشه در نظر گرفت که رم یه سری بلاک داره که توشون یه سری متغیر ذخیره میشه و هرکدوم از این خونه ها هم یک آدرس هگزادسیمال دارن
حالا نکته اینه که این بلاک های متغیر میتونن یک آدرس از یک بلاک دیگه رو توی خودشون داشته باشن
مثل این عکس:
پوینتر یا اشاره گر یه تایپ متغیره که دقیقا کارش اینه که توی خودش ادرس یک بلاک رم رو نگه داره
برای تعریف یه پوینتر کافیه بعد Type متغیر یه * بذارید (میشه پشت اسم متغیر هم گذاشت ولی معمولا همونجا که گفتم میذارن)
int num = 5; int* numPointer = num;
خروجی این کد یه چیزی مثل این خواهد بود که درواقع ادرس یک بلاک از حافظه هستش: 0x5053bc
حالا ما اگه بخوایم به وسیله آدرس به متغیر برسیم باید چیکار کنیم؟
کافیه پشت متغیر پوینترمون یه * بذاریم
cout<<*numPointer;
با این کار بجای اینکه آدرس حافظه رو به ما بده به اون ادرس میره و چیزی که تو اون بلاک مموری هست رو به ما برمیگردونه
خروجی این کد 5 هستش که همون مقدار متغیر num هست
به همین صورت میشه مقدار num رو هم تغییر داد
*numPointer = 10;
الان مقدار num رو اگه بگیریم 10 خواهد بود
حالا برای اینکه به لول بعدی از پوینتر بریم باید اینو بدونید که چون پوینتر خودش یه متغیره و یه جایی تو رم رو داره اشغال میکنه منطقن خودش هم یه ادرس داره که میشه مثل بقیه متغیر ها اینجوری بهش دست یافت
cout<<&numPointer;
خروجی این کد ادرس خود پوینتر تو رم هست و نه ادرس num!
(این قضیه تو عکس قبلی هم که گذاشتم مشخصه که پوینتر خودش هم یه بلاک حافظه و آدرس داره)
حالا که اینارو کنار هم بچینی فکر میکنی که پس میتونه یه پوینتر به یه پوینتر دیگه اشاره کنه؟
آره
ولی سینتکسش کمی متفاوته
باید موقع تعریف بجای یه دونه * دوتا * گذاشت
int** numPointerPointer = &numPointer;
ولی باید بدونید که نمیتونه یه پوینتر که داره پوینتر اشاره میکنه توی یه پوینتر دیگه ذخیره بشه یعنی اگه اینکارو کنی ارور میده:
int** numPointerPointerPointer = &numPointerPointer;
فقط یه نکته این وسط میمونه که ما میتونیم از توی پوینتری که پوینتر ذخیره میکنه بریم اون متغیر معمولی num رو در بیاریم، چجوری؟ اینجوری:
cout<<**numPointerPointer;
خروجی این کد 5 هست که محتوای num هستش و اگه بجای دوتا * فقط یکی میذاشتیم خروجی درواقع آدرس num بود که همون محتوای numPointer هستش
این ۰ تا ۱۰۰ پوینتر بود، بریم سراغ رفرنس
رفرنس ها شبیه پوینتر هستن ولی خیلییییی فرق دارن
رفرنس ها اصلا متغیر نیستن و این به معنای اینه که بلاکی براشون توی رم ساخته نمیشه که آدرس و محتوا داشته باشن
رفرنس فقط رفرنسه نه چیز دیگه اینجوری هم ساخته میشه:
کافیه یه & بذاری جلوی Type متغیر
int& numReference = num;
الان numReference به num رفرنس میده
حالا اگه ما بیایم مقدار numReference رو بگیریم
cout<<numRefreence;
میبینیم که خروجی محتوای همون متغیر رفرنس داده شده یعنی ۵ هست
حالا بنظرتون اگه ادرس numReference رو بگیریم با چه ادرسی مواجه میشیم؟
cout<<&numRefreence;
خروجی ادرس متغیر num خواهد بود، چون رفرنس اصلا چیزی نیست که توی رم بلاکی داشته باشه که اون بلاک آدرسی داشته باشه و فقط رفرنسه، پس اگه آدرسش رو هم بگیریم انگار داریم آدرس همون num رو میگیریم
حالا بنظرتون اگه بیایم مقدار رفرنس رو تغییر بدیم چه اتفاقی میوفته؟
numReference = 10; cout<<numReference; cout<<num;
خروجی این کد دو تا 10 خواهد بود
چرا؟ چون با تعیین مقدار numReference درواقع مقدار خود num رو تعیین کردیم
و این یعنی با تغییر محتویاط رفرنس خود رفرنس تغییر نمیکنه چون اصلا محتویاطی نداره و درواقع متغیری که ازش رفرنس گرفته تغییر پیدا میکنه که در اینجا num برابر با 10 شد
یه سوال، آیا میشه به یه رفرنس رفرنس داد؟ نچ!
امیدوارم بخوبی توضیح داده باشم و این مسئله به ظاهر پیچیده رو درک کرده باشید
اینم کل کد هایی که تو این مقاله با هم زدیم، میتونید کپی پیست کنی و خودتون تستش کنید:
#include <iostream> using namespace std; int main() { int num = 5; int* numPointer = # int** numPointerPointer = &numPointer; int& numReference = num; cout<<"num Value:"<<num<<endl; cout<<"num Address:"<<&num<<endl; cout<<endl<<endl; cout<<"numPointer Value:"<<numPointer<<endl; cout<<"numPointer Pointer Value:"<<*numPointer<<endl; cout<<"numPointer Address:"<<&numPointer<<endl; cout<<endl<<endl; cout<<"numPointerPointer Value:"<<numPointerPointer<<endl; cout<<"numPointerPointer Pointer Value:"<<*numPointerPointer<<endl; cout<<"numPointerPointer Address:"<<&numPointerPointer<<endl; cout<<"numPointerPointer Pointer Pointer Value:"<<**numPointerPointer<<endl; cout<<endl<<endl; cout<<"numReference Value:"<<numReference<<endl; cout<<"numReference Address:"<<&numReference<<endl; }
👋.