PDA

View Full Version : سوال: توضیح در مورد PChar و String و فرق متغیر و اشاره گر؟



mbshareat
دوشنبه 20 آبان 1387, 11:26 صبح
لطفا تفاوتهای PChar و String را برایم توضیح دهید.:متفکر:
اگر ممکن است در مورد کارکتر خالی انتهای رشته هم توضیح دهید که آیا ممکن نیست وسط رشته کارکتر کد صفر هم داشته باشیم ؟:چشمک:
یادم می آید که وقتی با فایل کار می کردم استفاده از این دو نوع نتایج متفاوتی داشت و در تبدیل این دو نوع هم مشکل جدی داشتم:گریه:
راستش من هنوز نفهمیده ام فرق بین متغیر و اشاره گر چیه چون هر دو به محلی از حافظه اشاره دارند.:متعجب:
اگه منو درمورد نوع داده رویه ای هم راهنمایی کنین و بگین به چه دردی می خوره هم خیلی ممنون می شم.:تشویق:

vcldeveloper
دوشنبه 20 آبان 1387, 15:55 عصر
string یک نوع داده مدیریت شده در دلفی هست. stringها و Dynamic Arrayها رفتاری مشابه هم دارند. یک string اشاره گری به یک ساختار داده در heap هست. این ساختار شامل فیلدهایی برای نگهداری تعداد ارجاعات به آن string، اندازه داده ذخیره شده در string، و آرایه ایی از بایت ها که داده مورد نظر را در خودش نگهداری میکنه، هست. ر انتهای این ساختار هم کارکتر #0 بصورت خودکار درج میشه. دلفی از روی فیلد مربوط به تعداد ارجاعات یک string متوجه میشه که کی باید اون string را از بین ببره؛ یعنی هر زمان تعداد ارجاعات به صقر برسه، string بطور خودکار حذف میشه. البته برای ثابت ها (Const) که بصورت string تعریف میشند، قضیه فرق میکنه؛ فیلد شمارشگر ارجاعات آنها مساوی -1 هست تا هیچ وقت پاک نشند.
قتی یک متغیر از نوع string تعریف می کنید، دلفی یک اشاره گر با مقدار nil میسازه. وقتی به متغیر مورد نظر مقداری اختصاص میدید؛ دلفی ساختار مورد نظر را در حافظه Heap ایجاد میکنه، مقدار مورد نظر شما را به آن منتقل میکنه، و اشاره گر مربوط به متغیر string را طوری تنظیم میکنه که به اون ساختار در Heap اشاره بکنه.
نوع داده PChar اشاره گریی به یک خانه حافظه هست، فقط با این خانه حافظه به عنوان یک Char برخورد میشه. از این نوع داده برای اشاره به داده های مختلفی استفاده میشه، بخصوص در Windows API ازش زیاد استفاده میشه. فرقش با string این هست که string به یک ساختار در حافظه اشاره میکنه، و بطور خودکار مدیریت میشه، ولی PChar فقط به یک بایت از حافظه اشاره میکنه، و مدیریت آن هم با کاربر هست. البته در دلفی نوع داده PChar و string با هم سازگار هستند، یعنی اگر مقدار یک PChar را به متغیری از نوع string اختصاص بدید، دلفی از بایتی که PChar به آن اشاره می کند، تا بایتی که حاوی #0 هست را در متغیر string مربوطه ذخیره می کند.


اگر ممکن است در مورد کارکتر خالی انتهای رشته هم توضیح دهید که آیا ممکن نیست وسط رشته کارکتر کد صفر هم داشته باشیم ؟
کارکتر تهی انتهای رشته بخاطر سازگاری با رشته های C در دلفی وجود داره، وگرنه رشته های پاسکال نیازی به اون کارکتر ندارند. می تونید وسط یک رشته از کارکتر تهی استفاده کنید، ولی نتیجه اش این میشه که کنترل هایی که داده های string را نمایش میدن، مثل Edit، فقط تا محلی که کارکتر تهی وجود دارد را نمایش میدند، و از ادامه رشته صرفنظر می کنند.


راستش من هنوز نفهمیده ام فرق بین متغیر و اشاره گر چیه چون هر دو به محلی از حافظه اشاره دارند.
دو نوع متغیر وجود داره، متغیرهایی که به داده ایی در Stack اشاره می کنند، و متغیرهایی که به داده ایی در Heap اشاره می کنند. متغیرهایی که به داده ایی در Stack اشاره می کنند، آدرس خودشان آدرس همون داده مورد اشاره هست، یعنی وقتی مثلا دارید i : integer، و i := 4 ، چهار بایت از حافظه stack برای داده 4 کنار گذاشته میشه، و هر وقت بنویسید i، به این چهار بایت دسترسی دارید.
اما متغیرهایی که به داده ایی در heap اشاره می کنند، خودشون چهار بایت (به اندازه یک Pointer) در Stack حافظه اشغال می کنند، ولی در این فضا فقط آدرس یک خانه ایی از حافظه در Heap نگهداری میشه. اگر به آن خانه مراجعه بشه، چیزی جز آن آدرس حافظه پیدا نمیشه. داده اصلی در داخل حافظه Heap قرار داده شده، و از طریق آن آدرس میشه بهش دسترسی داشت.
در دلفی تمامی داده های دینامیک در حافظه Heap نگهداری میشند، پس قتی داده ایی از نوع string، یا dynamic array تعریف می کنید، یا شی ایی از یک کلاس میسازید، یا با استفاده از توابعی مثل GetMem یا New حافظه ایی را درخواست می کنید، در واقع یک متغیر روی stack تعریف می کنید که حاوی آدرس خانه ایی از حافظه روی Heap هست، که داده اصلی را در خودش جا داده.


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

mbshareat
دوشنبه 20 آبان 1387, 22:57 عصر
از راهنمایی شما ممنونم .لطفا بفرمایید منظورتون از اینکه فرمودید:

متغیرهایی که به داده ایی در Stack اشاره می کنند، آدرس خودشان آدرس همون داده مورد اشاره هست چیه؟:خجالت:
آیا معنی آن این است که خود متغیر آدرس نداره و تنها مقدار متغیر آدرس داره ولی متغیر از نوع اشاره گر یک آدرس برای خانه ای از حافظه Heap داره که حاوی آدرس خانه ای دیگر در حافظه Stack است که مقدار را نگه می داره؟:متفکر:
در ضمن منظورم از متغیر رویه ای نوع procedural است.
یک سوال دیکه هم دارم ::لبخند:
آیا ممکنه پارامتری مانند Out V:Variant به روتین یا تابعی ارسال کرد و بعد با تعریف مثلا
Var PI:PVariant مقدار V را دستكاری كرد؟اگه میشه لطفا بفرمایید می توانم به این روتین
مقداری از نوع Integer بفرستم؟

vcldeveloper
سه شنبه 21 آبان 1387, 03:07 صبح
آیا معنی آن این است که خود متغیر آدرس نداره و تنها مقدار متغیر آدرس داره ولی متغیر از نوع اشاره گر یک آدرس برای خانه ای از حافظه Heap داره که حاوی آدرس خانه ای دیگر در حافظه Stack است که مقدار را نگه می داره؟

نه، اشتباه متوجه شدید. فکر کنم نیاز هست که شکلی رسم بشه تا مطلب بهتر فهمیده بشه. اگر فردا وقت شد، یک شکل برای فهم بهتر موضوع میکشم، اینجا میزارم.


اگه منو درمورد نوع داده رویه ای هم راهنمایی کنین و بگین به چه دردی می خوره

در ضمن منظورم از متغیر رویه ای نوع procedural است.
تعریف Eventها در کلاس ها، و فراخوانی برخی توابع (مثلا توابع API ویندوز) بصورت دینامیک. تقریبا مفهومی مشابه Delegate در #C هست.


آیا ممکنه پارامتری مانند Out V:Variant به روتین یا تابعی ارسال کرد و بعد با تعریف مثلا
Var PI:PVariant مقدار V را دستكاری كرد؟
در تاپیک دیگه ایی که درباره Variant پرسیده بودید، جواب دادم. ربطی به این تاپیک نداشت.

anubis_ir
سه شنبه 21 آبان 1387, 13:08 عصر
آقاي كشاورز لطفا اصلاحيه نسخه دلفي 2009 را هم لحاظ كنيد :)
چون مفهوم pchar در آن كلا فرق كرده.

vcldeveloper
سه شنبه 21 آبان 1387, 16:22 عصر
آقاي كشاورز لطفا اصلاحيه نسخه دلفي 2009 را هم لحاظ كنيد :)
چون مفهوم pchar در آن كلا فرق كرده.
مفهومش تغییری نکرده. قبلا PChar به PAnsiChar مپ میشد، الان به PWideChar مپ میشه. هنوز همون اشاره گر هست، فقط بجای Char تک بایتی، به Char دو بایتی اشاره میکنه.

vcldeveloper
چهارشنبه 22 آبان 1387, 03:57 صبح
برای روشن تر شدن مفهوم متغیرها، اشاره گرها، اشیاء، و نوع داده string، یک تصویر آماده کردم، به همراه یک سورس کد ساده. تصویر نمایی گرافیکی از نتایج حاصل از اجرای کد هست.
نکته ایی که باید بهش توجه بشه اینه که در این کد، و تصویر از نوع داده AnsiString برای نمایش رفتار نوع داده string استفاده شده. در نسخه های دلفی که قبل از دلفی 2009 منتشر شدند، نوع داده string = AnsiString هست، پس تصویر برای این نسخه ها ایرادی نداره. در دلفی 2009، نوع داده string = UnicodeString هست. تنها تغییری که این مسئله در تصویر ایجاد میکنه این هست که در صورت استفاده از string بجای AnsiString - در دلفی 2009 - متغیرهای S و PChar به دو بایت از حافظه اشاره می کنند، نه یک بایت. سایر رفتارهایشان مشابه هست.

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

25422

کد نوشته شده:


program TestVariableMemo;

{$APPTYPE CONSOLE}

uses
SysUtils;

var
//Various type of variables
i, j : integer;
P1, P2 : pointer; //Untyped pointers
S : AnsiString;
PCh : PAnsiChar; //Typed pointer
Obj : TObject;

//Writes info of the variables in console window.
procedure WriteResult(const Title: string; Padding : integer);
begin
Writeln('=== ' + Title + ' ===');
Writeln;
Writeln('i = ', i :Padding,', Address = $', IntToHex(Integer(@i), 2));
Writeln('j = ', j :Padding,', Address = $', IntToHex(Integer(@j), 2));
Writeln('P1 = ', IntToHex(Integer(P1),2) :Padding,', Address = $', IntToHex(Integer(@P1), 2));
Writeln('P2 = ', IntToHex(Integer(P2),2) :Padding,', Address = $', IntToHex(Integer(@P2), 2));
Writeln('S = ', S :Padding,', Address = $', IntToHex(Integer(@S), 2));
Writeln('PCh = ', IntToHex(Integer(PCh),2):Padding,', Address = $', IntToHex(Integer(@PCh),2));
Writeln('Obj = ', IntToHex(Integer(Obj),2):Padding,', Address = $', IntToHex(Integer(@Obj),2));
Writeln;
Writeln;
end;

begin
try
//Write the initialization values of the variables.
WriteResult(' Variables are initialized ',4);
try
//Give some arbitrary value to the variables.
i := 128;
j := 10;
P1 := @i;
GetMem(P2,SizeOf(Integer));
Move(j,P2^,SizeOf(Integer));
S := 'Test';
PCh := @S[1];
Obj := TObject.Create;
finally
//Now that the variables are changed, wirte their info again so that we can compare them
//with the initial info.
WriteResult('Store values in the variables',8);
//Free the dynamically allocated memories.
FreeAndNil(Obj);
FreeMem(P2);
//Wait for user input.
ReadLn;
end;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.