PDA

View Full Version : استفاده از اشاره گرها در Object Pascal (دلفی)



RezaBS
جمعه 15 فروردین 1382, 23:18 عصر
1. اشاره گرها چیستند؟
هیچ وقت نفهمیدم چرا وقتی افراد وارد حیطه برنامه نویسی میشوند، با شنیدن نام اشاره گرها (Pointers) وحشت میکنند؛ شاید چون هنوز خودم اشاره گرها را نشناخته ام!!!
اشاره گر را میتوان به معنای واقعی یک مفهوم اساسی در برنامه نویسی دانست، درک آن مشکل است ولی زمانی که آن را بشناسیم واقعا بهتر برنامه مینویسیم، شاید چون در خیلی از موارد عملکردها را حس میکنیم!
اشاره گرها یک نوع داده هستند مثل Integer،Char و همانند اینها که در واقع آدرسهای حافظه را ذخیره میکنند. مساله از این جهت مهم است که هر چیزی که استفاده میکنیم حتما یک محل دارد و بنابراین راه دسترسی به آن همین اشاره گرها هستند. ساده؛ اشاره گر به یک رشته (String) اشاره میکند، وقتی از یک شئ (Object) استفاده میکنیم یا حتی زمانی که یک رویداد (Event) را صدا میزنیم، همه و همه اشاره ای به یک اشاره گر هستند. فرض کنید میخواهیم در صفحه نمایش ایجاد افکتهای گرافیکی کنیم، این کار از طریق نوشتن مقادیر مورد نظر در نقاط صفحه نمایش (Pixels) امکان پذیر است، پس کافی است اشاره گری به اولین نقطه داشته باشیم و کل نقاط در اختیار ما هستند.
البته اشاره گرها در دلفی آنگونه که در زبانهای C و C++ مورد توجه هستند، استفاده نمیشود، خصوصا به این دلیل که در Object Pascal سعی شده تا حد امکان از درگیری مستقیم برنامه نویس با اشاره گرها جلوگیری شود.

2. چرا به اشاره گرها نیاز داریم؟
خوب! واقعا من به عنوان یک برنامه نویس چه نیازی به دانستن محل حافظه یک متغییر دارم!؟
یک جا نوشته بود: "اشاره گرها میتوانند به هر چیزی اشاره کنند، پس به آنها نیاز داریم!!!!!!!!!!"
شاید بد نبود به ایشان میگفتیم: چقدر باهوش!!!!
اما با کمی دقت میتوان فهمید که همین حرف در واقع اصلی است که به ما میفهماند چرا اشاره گرها را به کار میگیریم! شما میتوانید با اشاره گری به یک شئ اشاره کنید و آنرا تغییر دهید. بعد به راحتی با تغییر آدرس اشاره گر مربوطه به یک شئ دیگر اشاره میکنید و آنرا تغییر میدهید و داستان ادامه دارد تا خسته شوید! هر چیزی –و به معنای واقعی هر چیزی- که در یک برنامه استفاده میشود در محلی از حافظه قرار گرفته است.
جالب است اگر به این صورت به اشاره گرها نگاه کنیم که آدرس داده های برنامه را در زمان اجرا در اختیار ما قرار میدهند، حتی آنهایی که در زمان اجرا ایجاد شده اند و شاید حتی نام مشخصی هم نداشته باشند.

3. استفاده از اشاره گرها در دلفی
گفته شد اشاره گرها هم یک نوع داده هستند، پس باید امکان تعریف کردن آنها را داشته باشیم، اما چگونه؟
برای تعریف اشاره گرها از علامت ^ استفاده میشود. مثال زیر تعریف اشاره گری به یک داده از نوع Integer را نمایش میدهد:

Var
pntMyInt: ^Integer;
اما بعد از تعریف اشاره گر چگونه یک آدرس به آن نسبت دهیم؟ گفته شد اشاره گرها میتوانند به هر چیزی اشاره کنند، یک متغییر، یک تابع یا هر چیز دیگری، برای نسبت دادن هر کدام از اینها به یک اشاره گر از علامت @ استفاده میشود:

Var
tmpInt: Integer;
pntMyInt: ^Integer;
Begin

pntMyInt := @tmpInt;

End;
دقت شود کد فوق مقدار متغییر tmpInt را به pntMyInt منتقل نمیکند، بلکه فقط آدرس محل حافظه ای که tmpInt در آن قرار دارد را در pntMyInt ذخیره میکند. فرض کنید بخواهیم مقدار ذخیره شده در tmpInt را تغییر دهیم. کد زیر را ببینید:

Var
tmpInt: Integer;
pntMyInt: ^Integer;
Begin

tmpInt := 100;

pntMyInt := @tmpInt;

pntMyInt^ := 102;

End;
کد فوق را بررسی میکنیم؛ در ابتدای کار با استفاده از روش مقدار دهی مستقیم عدد 100 را به متغییر tmpInt نسبت دادیم. سپس در مراحل بعدی آدرس محل حافظه این متغییر را در اشاره گر pntMyInt ذخیره کردیم، توجه توجه! این کار با مساوی قرار دادن دو متغییر کاملا متفاوت است و در اینجا عدد 100 در اشاره گر ما قرار نمیگیرد.
اما pntMyInt^ := 102 به چه معنی است؟ خیلی راحت: عدد 102 را در محل حافظه ای که pntMyInt به آن اشاره دارد ذخیره کن، و آن محل حافظه جایی نیست جز متغییر tmpInt. چه اتفاقی افتاد؟ tmpInt := 102 ، به همین راحتی! هر گاه علامت ^ بعد از اشاره گر قرار گرفت مقدار ذخیره شده در آن محل حافظه مد نظر است.
خوب! پس ما میتوانیم محل حافظه ای که اشاره گر به آن اشاره میکند را بخوانیم یا بنویسیم (تغییر دهیم)، همچنین مقدار متغیری که در محل حافظه ای که اشاره گر به آن اشاره دارد را بخوانیم یا بنویسیم.
گفته شد که اشاره گرها به اشیاء هم اشاره میکنند پس نباید عجیب باشد اگر جایی ببینیم:

formPointer : ^TForm1;
اجازه دهید کمی درگیرتر شویم! با یک کد شروع میکنیم:


type
TMyObject = record
MyCode: Integer;
MyText: String;
end;

pntMyObject = ^TMyObject;

procedure CheckMyObjectPointer;
var
Object1, Object2: TMyObject;
Pointer2Object: pntMyObject;
begin
Pointer2Object := @Object1;
Pointer2Object^.MyCode := 25;
Pointer2Object^.MyText := 'First';

Pointer2Object := @Object2;
Pointer2Object^.MyText := 'Second';
end;

صبر کنید! هنوز برای فرار کردن خیلی زوده!
به نظر پیچیده هست ولی اگر کمی دقت کنیم خیلی هم مشکل نیست. بیایید با هم این کد را بررسی کنیم:
در قسمت تعریف داده ها یک نوع شئ شخصی تعریف شد، خیلی هم مهم نیست، شما میتوانید از اشیاء موجود دلفی استفاده کنید. اما در قسمت دوم تعریف انواع داده ها هم اتفاق خاصی نیافتاده است. این قسمت را اینجا آوردم تا با این حالت هم آشنا شوید. شما میتوانید انواع اشاره گرها را به این صورت استفاده کنید، در واقع در اینجا هر وقت در برنامه بخواهیم اشاره گری به TMyObject تعریف کنید به جای ^TMyObject به راحتی از pntMyObject استفاده میکنید. اما در رویه (Procedure) نوشته شده، ابتدا در بخش تعریف متغیرها دو شئ از نوع TMyObject تعریف میشود ونیز یک اشاره گر به همان نوع شئ. در ابتدای رویه اشاره گر با آدرس شئ اول تنظیم میشود و خیلی راحت بااستفاده از مواردی که در بالا گفته شد مقدار دهی میشود. سپس اشاره گر ما به شئ دوم نسبت داده میشود و آدرس محل حافظه شئ دوم در آن قرار میگیرد و باقی ماجرا...
خواص (Property) یک شئ را در نظر بگیرید که به این صورت قابل تغییر هستند!
شاید از خودتان بپرسید چرا من مسیر خود را طولانی کنم؟ گفته بودم که دردلفی نیاز به اشاره گرها مانند C و C++ احساس نمیشود، اما به شما میگویم گاهی این کار مسیر شما را خیلی بیشتر از آن چیزی که فکر میکنید کوتاه میکند، استفاده از بعضی توابع API را در نظر بگیرید...
4. اشاره گرهای عمومی در دلفی
تا اینجا از اشاره گرهایی استفاده کردیم که به نوع داده مشخصی اشاره داشتند، در این حالت دلفی به اندازه کافی باهوش هست که اشتباهات ما را در استفاده از اشاره گر به ما گوشزد کند. اما گاهی مجبوریم از اشاره گرهای بی نام و نشانی استفاده کنیم که به آنها اشاره گر عمومی میگوییم و قادرند به هر چیزی بدون در نظر گرفتن نوع آن اشاره کنند. این نوع اشاره گرها در دلفی به نوع داده ای Pointer اطلاق میشوند. به مثال زیر توجه کنید:


procedure CheckGenericPointer( const pntGPointer: Pointer);
var
tmpInt: ^Integer;
MyCode: Integer;
begin
tmpInt := pntGPointer;
MyCode := tmpInt^;

end;

procedure CallCheckProc;
var
MyInt: Integer;
begin
MyInt := 100;
CheckGenericPointer( @MyInt);
end;

در کد فوق دو مورد در نظر گرفته شده است، هم از اشاره گرهای عمومی استفاده شده و هم نشان داده شده است که چگونه میتوانیم از اشاره گرها به عنوان پارامتر توابع استفاده کنیم. نکته ای که باید در نظر بگیریم نحوه استفاده از اشاره گر عمومی است. یک اشاره گر عمومی ابتدا باید به یک اشاره گر دیگر نسبت داده شود تا قابل استفاده باشد. باقی موارد پیش از این بررسی شده اند. قبول دارم که استفاده از اشاره گرها در این کد منطقی نیست، پس کجا از اشاره گرهای عمومی استفاده کنیم؟ تا به حال از آرایه های پویا استفاده کرده اید؟ هر جایی که به نوعی با مفهوم حافظه پویا (Dynamic Memory) سر و کار داشته باشیم اشاره گرها به کمک ما می آیند، هر چند دلفی در اکثر این موارد نیز کار ما را آسان نموده است. برای نمونه TList را در نظر بگیرید، نگاهی به مثالهای همراه دلفی برای این کلاس بیاندازید، ضرر نمیکنید...

5. اشاره گرهای Nil
فکر نمیکنم کلمه مناسبی برای بیان این مفهوم پیدا شود. یک اشاره گر که به هیچ عنصری نسبت داده نشده باشد میتواند خطرناک باشد. اشاره گرها به ما اجازه میدهند مستقیما با حافظه کامپیوتر کار کنیم. خوب پس با اشاره گرهایی که –فعلا- به چیزی اشاره نمیکنند چه کنیم؟ راه حل این مشکل nil است. nil ثابتی (Constant) است که میتوانیم آنرا به هر اشاره گری نسبت دهیم. وقتی nil به اشاره گری نسبت داده شود، آن اشاره گر به جایی رجوع نمیکند مثل یک آرایه پویای خالی! به این صورت از بروز حوادث نامطلوب پیشگیری میکنیم. کد زیر نمونه این کار را نمایش میدهد:

pntMyPointer := nil;
طبیعی است که شما قصد استفاده از این اشاره گر را دارید بنابراین قرار نیست همواره به این حالت باقی بماند، بنابراین نیاز به کنترل آن در قسمتهای دیگر برنامه دارید، کد زیر را ببینید:

If pntMyPointer <> nil then

اگر nil بود آنرا به محل مورد نظر خود نسبت دهید. راه دیگر استفاده از تابع Assigned است:

If Assigned( pntMyPointer) Then

این مورد نیز در راهنمای همراه دلفی با مثال بررسی شده است.

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

موفق باشید...

مهرداد برنامه نویس
یک شنبه 29 شهریور 1383, 14:57 عصر
در دلفی چی؟

1485159
چهارشنبه 03 تیر 1388, 19:37 عصر
میشه بگید که از اشاره گر ها در کجا استفاده میشه؟؟
ممنون

من کلا از این اشاره گر ها بدم میاد آخه چرا باید استفاده کنیم؟
شاید کاربردشو نمیدنم...
کاربردش چیه؟
به طور کامل
ممنون