تماس درباره   صفحه اصلی
  ساختمان داده > حافظه پويا  
 
 

حافظه پويا و اشاره گرها


برای پياده سازی ساختارهای پويا از اشاره گرها استفاده می شود.

اعلان متغير اشاره گر
مقداردهی اولیه اشاره گر
عملیات اشاره گرها
تخصيص حافظه پويا
اشاره گر به آرايه
اشاره گر به رکورد


یک اشاره گر(Pointer) نوع خاصی از متغیر است که حاوی آدرسی از حافظه می باشد . درحالیکه يک متغیر استاندارد بايت هائی از حافظه را تعيين می کند که برای ذخيره نوع خاصی از داده کنار گذاشته شده است، متغير اشاره گر به بخش هایی از حافظه که توسط متغیر دیگری اشغال شده اشاره می کند.

اشاره گرها امکان استفاده از حافظه آزاد را فراهم می کنند. علاوه براين، به طور پويا در طی اجرای برنامه می توان آنها را ايجاد يا حذف کرد.

Pointer to Integer

از اشاره گرها برای ايجاد ساختمان داده های ديگر نظير لیست های پیوندی، پشته، صف و درخت های دودوئی استفاده می شود.


اعلان متغير اشاره گر

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

در زبان پاسکال، علامت (^) قبل از نوع داده قرار می گيرد تا متغيری را به عنوان اشاره گر معرفی کند.

در زبان C، علامت (*) برای نشان دادن اشاره گر بودن متغيری اضافه می شود. علامت ستاره را می توان بلافاصله بعد از نوع داده یا قبل از نام متغیر قرار داد.


مثال(Pascal). متغير اشاره گرPx به داده صحيحی اشاره می کند.

Px : ^Integer;

مثال(C). اشاره گر k به یک داده صحیح اشاره می کند.

int* k;  يا  int *k;

علامت ستاره به معنی داده ای است که k به آن اشاره می کند.


مقداردهی اولیه اشاره گر

نکته مهم هنگام کار با اشاره گرها مقدار دهی اولیه آنهاست. اگر یک اشاره گر را فقط اعلان کنید و بدون مقداردهی از آن استفاده کنید به محل نامعينی از حافظه اشاره کند و اين می تواند مشکلاتی را روی سیستم تولید کند.

یک روش کلی مقداردهی اشاره گر با مقدارصفر يا تهی (ثابت NULL در زبان C و ثابت nil در زبان پاسکال) است.

int *x=0;   يا  int *x=NULL;

راه معمول ديگر نسبت دادن آدرس يک متغير استاندارد، توسط عملگر آدرس، به يک متغير اشاره گر است.


مثال(C). به برنامه زير دقت کنيد.

#include <iostream.h>
void main()
{
int i;
int* j;
j = &i;
i = 10;
cout << "i is " i;
cout << "\n j is " << j << "\n";
}

آدرس متغير i توسط عملگر & بدست آمده و به اشاره گر j نسبت داده می شود، بنابراين j به متغیر i اشاره می کند. i يک متغير صحيح است و 4 بايت حافظه را اشغال می کند، j به اولین بایت از اين 4 بایت اشاره می کند.

Assign pointer with address of a variable

وقتی مقدار متغیر i چاپ می شود عدد 10 نمايش داده می شود. با چاپ متغير اشاره گر j یک عدد طولانی تر نشان داده می شود که آدرسی در حافظه است.


نکته. نوع اشاره گر و متغیری که به آن اشاره می کند باید یکسان باشد.


عملیات اشاره گرها

عملیات جمع و تفریق را می توان روی متغيرهای اشاره گر انجام داد. ضرب و تقسیم را روی یک اشاره گر نمی توان استفاده کرد. نکته مهمی که بايد به آن توجه کرد اين است که چون اشاره گر آدرسی در حافظه است وقتی عملیاتی که روی آن انجام می گیرد رفتار متفاوتی دارد. برای مثال عمل جمع اشاره گر را به تعداد بایت های نوع داده آن حرکت می دهد.


مثال(C). چون a اشاره گری به يک عدد صحیح است و نوع صحیح 4 بایت دارد با عمل افزایش 4 واحد به a اضافه می شود. يعنی به 4 بایت بعدی حافظه اشاره می کند و دیگر به همان 4 بایت قبلی اشاره نمی کند.

int *a;
a++;

مثال(C). اشاره گر p هشت بایت به جلو حرکت می کند و ديگر به متغير a اشاره نمی کند.

int a;
int *p;
p=&a;
p=p+2;


تخصيص حافظه پويا

اشاره گرها زمانی نقش مهمی را در برنامه بازی می کنند که بخواهیم یک تکه از حافظه پويا (Heap) را در حین اجرای برنامه به داده ای اختصاص دهیم. ناحيه Heap فضای آزاد حافظه در دسترس است که به صورت پويا استفاده می شود، يعنی در حين اجرای برنامه در صورت نياز اختصاص داده می شود و هنگامی که ديگر به آن احتياج نباشد آزاد می شود.

در زبان پاسکال توابع new و dispose برای تخصيص و بازپس گيری حافظه هنگام کار با حافظه پويا استفاده می شوند.


مثال(Pascal).

Var ptr:^Integer;
Begin
New(Ptr); {allocate memory to an Integer data}
{ Use ptr }
... Dispose(Ptr); {deallocate memory from the data}
End.


در زبان C++ دو عملگر new و delete برای اختصاص حافظه پويا بکار می روند.

دستور new تعداد بايت های معينی از حافظه پويا را به داده اختصاص می دهد. مقدار فضای مورد نیاز با توجه به نوع داده اشاره گر واگذار می شود.

اگر دستور new موفق باشد اشاره گری به فضای اختصاص داده شده بر می گرداند و اگر ناموفق باشد مقدار NULL را برمی گرداند. بعد از آن می توان از متغیر اشاره گر برای دسترسی به داده درصورت نیاز استفاده کرد.

وقتی فضای حافظه پویا دیگر مورد نیاز نباشد باید به حافظه آزاد برگردانده شود. دستور delete داده را از بين می برد و باعث می شود فضای حافظه آزاد شود تا برای مورد دیگری مجددا مورد استفاده قرار گیرد.


مثال(C). برای اختصاص فضا به یک داده صحیح دستورات زیر نوشته می شود:

int *IntPtr;
IntPtr=new int;
if (IntPtr!= NULL)
* IntPtr =55;


اگرچه بطور ایده ال فضای پویای اختصاص یافته به برنامه بعد از اتمام برنامه باید آزاد شود اما همیشه این اتفاق نمی افتد. یک برنامه که کلیه فضائی را که گرفته آزاد نمی کند دچار memory leaks است. نتيجه آن اين خواهد بود که بعد از اجرای برنامه حافظه آزاد کمتری نسبت به قبل از اجرا خواهيد داشت تا زمانی که کامپيوتر را راه اندازی مجددا کنيد. راه حل اصلی، پس گرفتن حافظه ای تخصيص داده شده در انتهای برنامه است.


اشاره گر به آرايه

معمولا یک اشاره گر به آرایه در برنامه زياد مورد استفاده قرار می گيرد. اشاره گر به آرایه به اولین بایت آن اشاره می کند. هر عملگر محاسباتی که روی آن انجام شود اشاره گر را به جلو و عقب آرایه حرکت می دهد.

#include <iostream.h>
void main ()
{
int i[5];
int *p;
p = i;
for ( int j = 0; j<5 ; j++,p++ ) {
   *p = j;
    cout << i[j];
   cout << "\n";
}
}


اشاره گر به رکورد

اشاره گر به رکورد يا ساختمان اجازه دسترسی به آن را مانند هر متغیر دیگری می دهد. تنها تفاوت در اينستکه چون رکورد یک نوع داده ترکیبی است هنگام دسترسی فيلد موردنظر در آن بايد تعيين شود.


مثال(C). ساختمان account به صورت زير تعريف شده است:

typdef struct account {
   float balance;
};
account *ptracout;

برای مقداردهی فيلد balance به صورت زير بايد عمل کرد:

ptraccount->balance=2000;

مثال(Pascal). Ptr اشاره گری به نوع رکورد CustRec است.

Type
Ptr=^CustRec;
CustRec = Record
   Code:Integer;
   Name:String[25];
   Address : String[50];
End;

برای دسترسی به فيلد Name دستور زير نوشته می شود:

Ptr^.Name := "Sara";


 


 


صفحه اصلی| PDF| درباره| تماس