معرفی Pointers برای برنامه نویسان
1396/09/29 12:24 , شایان مسلمی

معرفی Pointers برای برنامه نویسان

چه درک کنید یا خیر،تنوع زیاد برنامه هایی که تا الان استفاده کرده اید از چندراه باعث کاربرد pointers نیز میشود.شاید یک NullPointerException را تجربه کرده باشید.به عنوان یک برنامه نویس،کدهایی که مینویسید احتمالاً فراتر از استفاده از پوینترها هستند،حتی اگر خودتان آن ها را به کار نگرفته باشید.

امروز میخواهم به شما نشان بدهم که پوینترها چگونه کار میکنند،این مقاله بیشتر از حد معمول تئوریکال است،اما با ما همراه باشید،پوینترها بسیار پیچیده هستند!

کد کامپایلینگ

قبل از اینکه بحث را شروع کنیم،شما باید بدانید که کدها چگونه ساخته و پرداخته میشوند،شاید از قبل آن را میدانید.در این بخش از عبارات کلی استفاده خواهد شد،چیزهایی که برای اغلب زبان ها قابل پیاده سازی است،اما برای همه ی آن ها لازم نیست.

هر کامپیوتر از binary استفاده میکن،یک سری از ارقام صفر و یک که تکنولوژی مدرن را همانطور که میدانیم میسازد.خلی دشوار است که هرچیزی را بتوان به صفر و یک کدنویسی کرد،این ها دستورالعمل های خامی هستند که توسط واحد پردازشگر مرکزی (CPU) مورد نیاز هستند.این به عنوان Machine Code شناخته میشود.

گام بعدی از ماشین کد ، Assembly است.این فرمتی است ک برای انسان قابل خواندن است،در حالی که هنوز هم برای برنامه نویسی دشوار است،اما امکان پذیر می باشد.اسمبلی از یک سری دستورات ساده برای اجرای فعالیت ها تشکیل شده است و به عنوان زبان برنامه نویسی low level  یا سطح پایین شناخته میشود.امکان نوشتن برنامه های پیچیده وجود دارد،اما بیان مفاهیم انتزاعی سخت است و نیازمند بررسی است.

بسیاری از بازی های ویدیویی و برنامه های با عملکرد بالا،لاجیکی نوشته شده بر اساس اسمبلی دارند،اگر بدانید چه کاری دارید انجام میدهید،سرعت کار افزایش پیدا میکند.با این حال،برای اغلب پروژه های وسیع برنامه نویسی، شما اصلاً به اسمبلی احتیاج نخواهید داشت.

پس اگر ماشین کد نوشتنش دشوار است،و برنامه نویسی اسمبلی نیز خیلی سخت است،شما با چه چیزی کد مینویسید؟ در اینجا بحث زبان های high level یا سطح بالا پدید می آید.زبان های سطح بالا نوشتن برنامه ها را ساده میکنند.شما میتوانید در چیزی برنامه نویسی کنید که به زبان مادری تان شبیه باشد و بیان الگوریتم های پیچیده در آن ساده باشد.شاید از زبان های سطح بالا زیاد شنیده باشید (و قطعاً از برنامه ای استفاده کرده اید که توسط این زبان ها نوشته شده باشد) :

  • BASIC
  • C++
  • Lisp

این زبان ها در حال حاضر خیلی قدیمی اند.یک کامپایلر برنامه ای است که زبان سطح بالای شما را به فرمی تبدیل میکند که قابل اجرا باشد.این میتواند یک زبان سطح بالای دیگر باشد،اما معمولاً اسمبلی است.برخی از زبان ها(مثل پایتون و جاوا) کد شما را یه یک حد واسط به نام bytecode تبدیل میکنند.این بعداً دوباره به کامپایل کردن نیاز خواهد داشت،که به صورت معمول بر اساس درخواست انجام میپذیرد،مثلاً زمانی که برنامه اجرا میشود.این به عنوان کامپایل کردن just in time شناخته میشود و کاملاً امری معمول است.

مدیریت حافظه

حالاکه میدانید زبان های برنامه نویسی چگونه کار میکنند،بیایید به مدیریت حافظه در زبان های سطح بالا بپردازیم.برای این مثال ها،من از pseudo code استفاده میکنم،کدی که در هیچ زبانی نوشته نشده،اما برای نشان دادن مفاهیم نسبت به ترکیب دقیق مورد استفاده قرار میگیرد.امروز،این بیشتر C++ را به بهترین زبان سطح بالا تشبیه میکند(البته از نظر بنده)!

بیشتر زبان ها متغیر دارند، یعنی محفظه هایی که برخی داده ها را ذخیره میکنند.شما باید به طور واضح نوع داده را تعریف کنید.برخی از زبان های که به صورت پویا نوشته شده اند،مثل پایتون یا PHP اینکار را برای شما انجام میدهند،اما هنوز هم ناچار به انجامش هستند.

فرض کنید که یک متغیر دارید:

int myNumber;

این کد بیانگر این است که شما متغیری به نام myNumber دارید و یک دیتاتایپ integer را به آن میدهد.زمانی که کامپایل شد،کامپیوتر این دستور را به عنوان زیر تفسیر میکند:

"کمی فضای خالی پیدا کنید و یک فضای بزرگ را برای نگه داری از یک integer اختصاص بدهید."

زمانی که این دستور اجرا شد،آن قسمت از مموری نمیتواند توسط یک برنامه ی دیگر استفاده بشود.هنوز شامل هیچ داده ای نیست،اما برای متغیر myNumber شما رزرو شده است.

حالا به متغیرتان مقدار بدهید:

myNumber = 10;

برای کامل کردن این کار، کامپیوتر شما به محل حافظه ی رزرو شده دسترسی پیدا میکند و هر مقداری که در آن هست را به مقدار جدید تغییر میدهد.

حالا دیگر این خوب و کامل شده است،اما چگونه موقعیت های حافظه چگونه ار زرزرو شدن خارج میشوند؟ اگر برنامه ها تمام حافظه ای را که میخواهند رزرو کنند،RAM به سرعت پر خواهد شد و در نتیجه سرعت سیستم کاهش چشمگیری پیدا خواهد کرد.

برای جلوگیری از چنین مشکلی، بسیاری از زبان ها از garbage collector یا آشغال جمع کن استفاده میکنند،این برای نابودسازی متغیرهایی که از اسکوپ خارج شده اند ( و در نهایت آزادسازی فضای رزرو شده) کاربرد دارد.

شاید شما تعجب کنید که اسکوپ چیست و چرا اهمیت دارد.اسکوپ محدودیت ها و طول عمر متغیرها یا هر حافظه ای که توسط یک برنامه استفاده شده باشد را تعریف میکند.زمانی که یک متغیر خارج از اسکوپ است یعنی توسط هیچ کد دیگری نمیتوان به آن دسترسی داشت( در اینجا آشغال جمع کن وارد میشود).مثال زیر را در نظر بگیرید:

function maths() {

    int firstNumber = 1;

}

 

int secondNumber = 2;

print(firstNumber + secondNumber); // will not work

این مثال کامپایل نمیشود.متغیر firstNumber در قسمت maths،اسکوپ است.این متغیر نمیتواند از بیرون ازقابلیت اعلام شده (maths) دسترسی داشته باشد.این یک مفهوم مهم در حوزه ی برنامه نویسی است و درک آن برای افرادی که با پوینترها کار میکنند حیاتی می باشد.

این راه اداره کردن مموری stack نامیده میشود.این راهی است که بسیاری از برنامه ها کار میکنند.شما حتماً نباید پوینترها را بشناسید تا بتوانید از آن ها استفاده کنید و نسبتاً خوب ساخته شده است.عیب استک سرعت آن است.همانطور که کامپیوتر باید حافظه را به چیزی اختصاص بدهد،از متغیرها آگاه باشد و آشغال جمع کن را به کار گیرد.این برای برنامه های کوچکتر خوب است،اما در مورد کارهای عملکرد بالا یا برنامه های سنگین قضیه از چه قرار است؟

پوینترها

روی کاغذ، پوینترها ساده به نظر میرسند.آن ها به یک موقعیت در مموری اشاره میکنند.این ممکن است تفاوتی با متغیرهای "معمولی" نداشته باشد، اما در حقیقت مغایرت عظیمی وجود دارد.پوینترها روی heap نگهداری میشوند.این مخالف stack است،ترتیب بندی کمتری دارد اما سرعت خیلی بالاتری دارد.

بیایید به چگونگی اختصاص دادن متغیرها روی stack نگاهی بیندازیم:

int numberOne = 1;

int numberTwo = numberOne;

این ترکیب ساده ای است:متغیر numberTwo شامل شماره یک است. متغیر آن در طول واگذاری از متغیر numberOne کپی شده است.

اگر بخواهید مموری آدرس یک متغیر را بگیرید،بجای مقدار آن،باید از & استفاده کنید.این به عنوان آدرس اپراتور شناخته میشود،و یک قسمت لازم از ابزار پوینتر شما است.

int numberOne = 1;

int numberTwo = &numberOne;

 

حالا متغیر numberTwo ، نسبت به شماره یک کپی شده در محل جدید مموری،به یک محل مموری دیگر اشاره میکند.اگر بخواهید از این متغیر خروجی بگیرید،شماره یک نخواهد بود(حتی اگر در محل حافظه ذخیره شده باشد).خروجی،محل مموری NumberTwo خواهد بود (احتمالاً چیزی مثل 2167، اگرچه بسته به سیستم و رم در دسترس متغیر است).برای دسترسی به مقدار ذخیره شده در یک پوینتر،به جای محل مموری ،شما باید پوینتر را ارجاع دهید.این باعث دسترسی مستقیم به مقدار خواهد شد که در اینجا شماره یک است.طریقه ی ارجاع یک پوینتر:

int numberTwo = *numberOne;

اپراتور ارجاع (dereference operator) یک ستاره (*) است.

درک این مفهوم میتواند دشوار باشد،پس بیایید دوباره با هم مرور کنیم:

  • آدرس اپراتور (&) آدرس مموری را ذخیره میکند.
  • ارجاع اپراتور (*) دسترسی به مقدار را ممکن میکند.

در زمان اعلام کردن پوینترها، ترکیب کمی تغییر میکند:

int * myPointer;

نوع داده ی int در اینجا به نوع داده ای برمیگردد که پوینتر به آن اشاره دارد،نه نوع خود پوینتر.

حالا که میدانید پوینترها کدامند،میتوانید ترفندهای خوبی با آن ها اجرا کنید!زمانی که حافظه در حال استفاده است،سیستم عامل شما به صورت متوالی شروع به کار میکند.شما میتوانید RAM را به عنوان لانه های کبوتر در نظر بگیرید.لانه های زیادی برای ذخیره ی چیزها وجود دارد،ولی تنها یکی به صورت فوری میتواند مورد استفاده قرار بگیرد.تفاوتی که اینجا وجود دارد این است که،این لانه های کبوتر شمارش شده هستند.در زمان اختصاص دادن مموری،سیستم عامل شما با کمترین شماره آغاز به کار میکند و بین شماره های تصادفی پرش نمیکند.

در زمان کار با پوینترها،اگر یک آرایه را اختصاص بدهید،با گستردن پوینتر میتوانید به راحتی به سمت المنت بعدی حرکت کنید.

کورد جالب در اینجا قرار دارد.وقتی شما مقادیر را به یک قابلیت(function) رد میکنید(با استفاده از متغیرهایی ذخیره شده در stack)،این مقادیر در داخل قابلیت شما کپی میشوند.،اگر متغیرها بزرگ باشند،برنامه ی شما دوبار آن ها را ذخیره میکند.وقتی قابلیت به پایان برسد،شما به راهی نیاز خواهید داشت که این مقادیر را بازگردانید.قابلیت ها میتوانند به صورت کلی یک چیز را برگردانند،بنابراین اگر بخواهید دو،سه یا چهار چیز را برگردانید،باید چه کرد؟

اگر شما یک پوینتر را به قابلیتتان pass کنید، فقط آدرس مموری کپی میشود.این باعث حفظ CPU شما میشود.شاید پوینتر شما به یک آرایه ی تصویری بزرگ اشاره دارد،قابلیت شما فقط روی داده ی دقیق و مشابه ذخیره شده در محل مموری مشابه کار نمیکند،بلکه زمانی که انجام بشود،نیازی به بازگشت هیچ چیز نیست!

شما باید مراقب باشید!پوینترها هنوز هم میتوانند از اسکوپ خارج شوند و توسط آشغال جمع کن ها جمع آوری شوند.مقادیری که در حافظه ذخیره میشوند،جمع آوری نمیشوند.این افشای مموری نام دارد.شما دیگر نمیتوانید به داده ها دسترسی داشته باشید (چون پوینترها از بین رفته اند)،اما هنوز هم از مموری استفاده میکند.این یک دلیل معمول برای کرش کردن برنامه هاست و اگر حجم داده ها زیاد باشد،میتواند شکست بخورد.اغلب اوقات، سیستم عامل شما،در صورت افشای زیاد (استفاده از رَم بیشتر نسبت به رم موجود در سیستم) برنامه ها را قطع میکند،اما این کار زیاد مطلوب به نظر نمی آید.

 

عیب یابی پوینترها یک کابوس است!مخصوصاً اگر در حال کار با مقادیر زیادی از داده ها باشید یا روی لوپ ها کار کنید.معایب آن ها و دشواری شناخت آن ها را در ازای پیشرفت عملکردی میتوانید قبول کنید.اگرچه به یاد داشته باشید که همیشه آن ها مورد نیاز نیستند.

این بحث امروز بود.امیدوارم که درباره ی این مبحث پیچیده توانسته باشید چیزهای مفیدی را یاد بگیرید.البته ما همه ی چیزهای مربوطه را پوشش ندادیم چون این بحث واقعاً سنگین است.

اگر یادگیری این بحث ها برای شما خیلی دشوار است،میتوانید از زبان های ساده تر برنامه نویسی استفاده کنید.

نظر شما درمورد نحوه ی کار پوینترها چیست؟اگر نکته یا ترفندی در اینباره میدانید در قسمت نظرات با ما به اشتراک بگذارید.

 

منبع : MakeUseOf

از آخرین دوره های آموزشی و تخفیف ها مطلع شوید

با تکمیل فرم زیر ، از اخبار و اطلاعات به روز برنامه نویسی و تکنولوژی عقب نمانید

آخرین مطالب

آموزش جامع SQL Server (جلسه ۱۲)
آموزش جامع SQL Server (جلسه ۱۲)

دستور UPDATE در SQL Server برای تغییر داده‌های موجود در یک جدول، از دستور UPDATE به شکل زیر استفاده ...

آموزش جامع SQL Server (جلسه ۱۵)
آموزش جامع SQL Server (جلسه ۱۵)

دستور DROP TABLE در SQL Server گاهی، لازم است یک جدول که دیگر استفاده‌ای ندارد را حذف کنید. برای ...

آموزش جامع SQL Server (جلسه ۳۵: Window Functionها – بخش ۲)
آموزش جامع SQL Server (جلسه ۳۵: Window Functionها – بخش ۲)

بخش اول از آخرین مبحث دوره جامع آموزش SQL Server در جلسه قبلی بررسی شد. این مبحث که ...

آخرین دیدگاه ها

دیدگاه خود را درباره این پست بنویسید

فرم ارسال نظرات