در آموزش قبل در مورد اشاره‌گرها صحبت شد و مفاهیم مربوط به اشاره‌گرها ارائه شد. در این نوشته نکات تکمیلی اشاره‌گرها تخصیص حافظه پویا در c++ را بیان می‌کنیم.

این آموزش را با یک مثال شروع می‌کنیم. کد زیر را درنظر بگیرید:

#include <iostream>

using namespace std;

void f(int A[],int n);
int main(){
	int const n=3;
	int i,A[n];
	
	for(i=0;i<n;i++)
		A[i] = i+1;
		
	f(A,n);
	
	for(i=0;i<n;i++)
		cout<<A[i];		
}

void f(int A[],int n){
	int i;
	
	for(i=0;i<n;i++)
		A[i] = A[i] + 1;
}

در کد بالا یک آرایه سه تایی داریم که در خط 10 و 11 به ترتیب با 1و 2 و 3 مقداردهی میشود. سپس این آرایه به تابع f ارسال می‌شود و در این تابع به هر خانه آرایه یک واحد اضافه می‌شود. با توجه به این توضیحات به نظرتان در خط 15 و 16 چه اعدادی چاپ می‌شوند؟
اگر بخواهیم با توجه به معلومات آموزش قبل (که در مورد متغیرهای محلی صحبت شد) پاسخ دهیم قاعدتا همان اعداد 1 و 2 و 3 باید چاپ شود و تغییراتی که در تابع f ایجاد شده است در خط 15 و 16 دیده نمی‌شوند، اما اگر این کد را اجرا کنید خواهید دید که اعداد 2 و 3 و 4 چاپ خواهند شد. اما علت چیست؟
جواب سوال چندان دور از انتظار نیست. نام آرایه، خود یک اشاره گر است که به اولین خانه آرایه اشاره میکند. شاید این سوال پیش بیاید که در آموزش قبلی برای اشاره گرها از * استفاده میکردیم، پس چرا در آرایه * نداریم؟
در پاسخ باید گفت پیاده سازی آرایه در ++c به این صورت نوشته شده است و در استفاده از نام آرایه نیازی به نوشتن * نیست، ولی از نظر مفهومی همان اشاره‌گر است! یعنی A به اولین خانه آرایه A اشاره‌ می‌کند. نکته بعدی اینکه بد نیست بدانید که به جای A[0] میتوانیم بنویسیم A*، یا به جای A[1] میتوانیم بنویسیم (A+1)* . در مورد این نکته ضرورتی نمیبینیم توضیح بیشتر دهیم، چون ممکن است شما را گیج کند. اما نکته مهمی که باید همیشه مد نظر داشته باشید این است که در استفاده از آرایه ها چنانچه از توابع استفاده می‌کنید حواستان به مفهوم اشاره گرها باشد. یعنی تغییراتی که در یک تابع بر روی آرایه می‌دهید، در تابع int main یا جایی که این تابع را فراخوانی کرده اید نیز اعمال می‌شود.

تخصیص حافظه پویا در c++

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

برای درک بهتر قدم به قدم جلو می‌رویم! در ++C تابعی به نام malloc وجود دارد که مخفف memory allocation یا همان تخصیص حافظه است. با استفاده از این تابع می‌توان در حین اجرای برنامه یک حافظه به میزانی که نیاز داریم از کامپایلر درخواست کنیم. مثلا دستور malloc(sizeof(int)) به این معنی است که شما درخواست یک حافظه به اندازه یک متغیر int نیاز دارید. کد زیر را ببینید:

int *p;	

p = (int *)malloc(sizeof(int));	
یوتیوب
در آموزش یوتیوب از دستور new استفاده کردم

در خط 1 اشاره گر p تعریف شده است. در خط 3 یک حافظه به اندازه int از کامپایلر درخواست شده است. کامپایلر این حافظه را به برنامه اختصاص می‌دهد و آدرس این حافظه را در اشاره گر p ذخیره می‌کند. بنابراین چنانچه بخواهیم به محتوای این حافظه دسترسی داشته باشیم از p* استفاده میکنیم. کد زیر را ببینید:

#include <iostream>

using namespace std;

int main(){
	int *p;
	
	p = (int *)malloc(sizeof(int));
	
	*p = 10;
	
	cout<<*p;
	
	free(p);		
	
}


همانطور که در بالا اشاره شد در خط 8 یک حافظه به صورت پویا به برنامه اختصاص داده می‌شود و آدرس این حافظه در اشاره گر p ذخیره می‌شود. حال به راحتی می‌توانیم با این اشاره گر به محتوای حافظه دسترسی داشته باشیم. مزیت استفاده از این روش را در خط 14 میبینیم. جایی که کارمان با حافظه تمام شده است و با دستور free می‌توانیم حافظه را آزاد کنیم. پس دو تابع مهمی که در این قسمت آموختیم malloc و free است. malloc برای اختصاص حافظه و free برای آزاد کردن حافظه!

دانشجویان کامپیوتر این کاربرد از اشاره‌گرها را در درس ساختمان داده به وفور مشاهده می‌کنند!

مباحث دیگری نیز در اشاره‌گرها باقی‌مانده است که همچنان می‌توان در مورد آنها صحبت کرد اما با توجه به اینکه آن نکات در زبانهای دیگر برنامه‌نویسی کمتر دیده شده است به همین میزان از مفاهیم اشاره گر بسنده می‌کنیم.

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