PDA

View Full Version : مشکل این کد چیه؟



1485159
سه شنبه 28 اردیبهشت 1389, 23:41 عصر
سلام
مشکل این کد چیه؟

var
x: array[0..10] of TStringList;
begin
for I := 0 to 10 do
begin
if Assigned(x[i]) then
begin
x[i].Free;
end;
end;
end;

Mahmood_M
چهارشنبه 29 اردیبهشت 1389, 00:10 صبح
خوب ، چی میشه ؟ چه اتفاقی می افته ؟

Felony
چهارشنبه 29 اردیبهشت 1389, 00:33 صبح
خوب ، چی میشه ؟ چه اتفاقی می افته ؟

پیغام خطا AV میده ، دلیلش این هست که کلاس TStringList به طور پیش فرض با nil مقدار دهی نشده و وقتی شما با تابع Assigned چکش میکنید در حقیقت شیئی که هیچ اشاره گری در حافظه براش در نظر گرفته نشده رو به تابع Assigned ارجاع دادید و تابع آدرس حافظه ای که در محدوده دسترسی برنامه نیست رو چک میکنه و خطای AV رخ میده .
کدتون رو به صورت زیر تغییر بدید :
var
x: array[0..10] of TStringList;
i: Byte;
begin
for I := 0 to 10 do
begin
x[i]:= nil;
if Assigned(x[i]) then
begin
x[i].Free;
end;
end;
end;

AliReza Vafakhah
چهارشنبه 29 اردیبهشت 1389, 00:56 صبح
پیغام خطا AV میده ، دلیلش این هست که کلاس TStringList به طور پیش فرض با nil مقدار دهی نشده و وقتی شما با تابع Assigned چکش میکنید در حقیقت شیئی که هیچ اشاره گری در حافظه براش در نظر گرفته نشده رو به تابع Assigned ارجاع دادید و تابع آدرس حافظه ای که در محدوده دسترسی برنامه نیست رو چک میکنه و خطای AV رخ میده .
کدتون رو به صورت زیر تغییر بدید :
var
x: array[0..10] of TStringList;
i: Byte;
begin
for I := 0 to 10 do
begin
x[i]:= nil;
if Assigned(x[i]) then
begin
x[i].Free;
end;
end;
end;

خوب این طوری شرط حلقه دیگه اجرا نمیشه ! چون هر x ای از آرایه TStringList قبلش nil میشه

Felony
چهارشنبه 29 اردیبهشت 1389, 01:28 صبح
خوب این طوری شرط حلقه دیگه اجرا نمیشه ! چون هر x ای از آرایه TStringList قبلش nil میشه
اون nil فقط یک نمونه بود تا توضیحاتی که دادم مفهوم باشه ، من که نگفتم تو برنامه این کار رو بکنید !

کد زیر رو ببینید :
var
x: array[0..10] of TStringList;
i: Byte;
begin
for i := 0 to 10 do
X[i]:= TStringList.Create;
for i := 0 to 10 do
if Assigned(x[i]) then
x[i].Free;
end;

وقتی شیئی وجود خارجی نداره چه طور به وسیله تابع Assigned میخواین بررسی کنیدش ؟
تابع Assigned اشاره گر مربوط به یک شئ رو چک میکنه که آیا به جایی اشاره داره یا نه .

در ضمن با استفاده از متد Free یک کلاس شئ آزاد میشه و دیگه اشاره گری بهش اشاره نمیکنه پس یعد از آزاد سازی اگر با تابع Assgined شئ رو به صورت زیر چک کنیم با پیغام خطا Invalid Pointer مواجه میشیم :
var
x: array[0..10] of TStringList;
i: Byte;
begin
for i := 0 to 10 do
begin
X[i]:= TStringList.Create;
x[i].Free;
end;

for i := 0 to 10 do
if Assigned(x[i]) then
x[i].Free;
end;

برای رفع این مشکل هم میتونید از تابع FreeAndNil استفاده کنید که بعد از آزاد سازی شئ اشاره گر اون به nil اشاره کنه :
var
x: array[0..10] of TStringList;
i: Byte;
begin
for i := 0 to 10 do
begin
X[i]:= TStringList.Create;
FreeAndNil(X[i]);
end;

for i := 0 to 10 do
if Assigned(x[i]) then
FreeAndNil(X[i]);
end;

1485159
چهارشنبه 29 اردیبهشت 1389, 09:33 صبح
حالا فرض کنید که من یه آرایه 100 عضوی از کلاس TStringList دارم.و هنگام اجرا هم با توجه به بعضی شرایط ممکنه بعضی ها create بشن و بعضی ها نشن! در آخر برای این که حافظه رو آزاد کنم باید هرکدوم رو که create کردم از بین ببرم...
در اینصورت اول باید از 1 تا 100 کلاس همشون رو به nil تبدیل کنم، بعد هرکدوم رو که خواستم create کنم و بعد برای آزاد سازی چک کنم؟

Mahmood_M
چهارشنبه 29 اردیبهشت 1389, 09:38 صبح
پیغام خطا AV میده ، دلیلش این هست که کلاس TStringList به طور پیش فرض با nil مقدار دهی نشده و وقتی شما با تابع Assigned چکش میکنید در حقیقت شیئی که هیچ اشاره گری در حافظه براش در نظر گرفته نشده رو به تابع Assigned ارجاع دادید و تابع آدرس حافظه ای که در محدوده دسترسی برنامه نیست رو چک میکنه و خطای AV رخ میده .
کدتون رو به صورت زیر تغییر بدید :
مشکل این کد مربوط به Assigned نیست ، اگر قرار باشه فقط مقادیری که در حافظه فضایی دارن رو به Assigned اختصاص بدیم که دیگه Assigned مفهومی پیدا نمی کنه ! اون تابع درواقع چک می کنه که پارامتر ارسالی آدرسی در حافظه داره یا نه ...
در کد بالا هم آدرس داده میشه ، یعنی وقتی آرایه تعریف میشه خانه ی حافظه برای اعضای آرایه اختصاص داده میشه ، پس تابع Assigned هم مقدار True رو بر می گردونه ، AV ای که ظاهر میشه به خاطر این خط از کد هست :
x[i].Free;
چون [X[I هنوز Create نشده ، پس نمی تونه Free بشه ، ولی خانه ی حافظه براش درنظر گرفته شده و در واقع به آدرس از حافظه اشاره می کنه ...
وقتی یک شیء برابر با Nil قرار می گیره دیگه به آدرسی اشاره نخواهد کرد ، پس اگر یک شیء Nil شده رو به Assigned بدید مقدار False برگشت داده میشه ، حتی اگه شیء Free شده باشه ، باز هم آدرسی در حافظه داره ، فقط اون فضا اشغال نشده هست ، و اگر شیء Free شده رو هم به Assigned بدید باز هم مقدار True برگشت میده ...
برای اینکه بخواید شیء تون آزاد بشه و همچنین دیگه به آدرسی هم اشاره نکنه باید اون رو بعد از Free کردن برابر nil قرار بدید یا اینکه از FreeAndNil استفاده کنید ...
ویرایش : اشتباه شد ! ( و پاک شد ! )

سلام
مشکل این کد چیه؟
اگر در حلقه به جای قرار دادن مستقیم عدد از توابع Low و High استفاده کنید دیگه مشکلی نیست ، لازم به استفاده از Assigned هم نیست ، ولی به مواردی که در مورد Free و Nil گفته شد دقت کنید ( مثلا بعد از Free کردن در حلقه اونها رو Nil کنید یا از FreeAndNil استفاده کنید )

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

Felony
چهارشنبه 29 اردیبهشت 1389, 09:51 صبح
مشکل این کد مربوط به Assigned نیست ، اگر قرار باشه فقط مقادیری که در حافظه فضایی دارن رو به Assigned اختصاص بدیم که دیگه Assigned مفهومی پیدا نمی کنه ! اون تابع درواقع چک می کنه که پارامتر ارسالی فضایی رو اشغال کرده یا نه ...
در کد بالا هم فضا اشغال میشه ، یعنی وقتی آرایه تعریف میشه خانه ی حافظه برای اعضای آرایه اختصاص داده میشه ، پس تابع Assigned هم مقدار True رو بر می گردونه ، AV ای که ظاهر میشه به خاطر این خط از کد هست :
1.
x[i].Free;

چون [X[I هنوز Create نشده ، پس نمی تونه Free بشه ، ولی خانه ی حافظه براش درنظر گرفته شده و در واقع به آدرس از حافظه اشاره می کنه ...
:چشمک:منظور من هم همین بود ولی مثل اینکه درست منظورم رو نرسوندم ، خوب معلومه که اشکال از Free هست چون شئ ساخته نشده که بخواد آزاد بشه .


برای کار با آرایه ها دو تابع جالب به نامهای Low و High در دلفی وجود داره ، این دو تابع کمترین و بیشترین مقادیر یک آرایه ( یا ... ) که آدرسی در حافظه دارند رو مشخص می کنن ، یعنی مقادیری که Nil نشدن و آدرسی در حافظه دارن ...
کار این دو تابع این هست که میگن آرایه از چه خانه ای شروع و به چه خانه ای ختم میشه ، همین .


اگر در حلقه به جای قرار دادن مستقیم عدد از توابع Low و High استفاده کنید دیگه مشکلی نیست ، لازم به استفاده از Assigned هم نیست ، ولی به مواردی که در مورد Free و Nil گفته شد دقت کنید ( مثلا بعد از Free کردن در حلقه اونها رو Nil کنید یا از FreeAndNil استفاده کنید )
چرا لازم به استفاده از تابع Assigned نیست ؟
همونطور که گفتم توابع Low و High فقط عنصر اول و عنصر آخر یک آرایه رو برمیگردونن ( برای استفاده در قسمت هایی از برنامه که آرایه پویا تعریف شده و در قسمتی دیگر نیاز به دونستن طول آرایه داریم ) .

Felony
چهارشنبه 29 اردیبهشت 1389, 10:06 صبح
:چشمک:آقا من یه چیز دیدم خودم توش موندم !

این کد رو ببین محمود جان :
var
i: Byte;
x: array[0..100] of TStringList;
begin
for i := 0 to 100 do
if i mod 2=0 then
X[i]:= TStringList.Create;

for i := 0 to 100 do
if Assigned(x[i]) then
x[i].Free;
end;
طبق کد باید شئ TStringList یکی در میون ساخته بشه ولی دیباگش کن ببین چی ساخته شده !

حالا آرایه رو به بخش Var یونیت منتقل کن و دیباگ کن ، درست پر میشه !

دلیل به وجود اومدن این مشکل تعریف آرایه هست ، حالا چرا اینجوری میشه رو سر در نمیارم ( با این تفاصیر تمام گفته های قبلی من و شما نقض میشه ) :قهقهه:

Mahmood_M
چهارشنبه 29 اردیبهشت 1389, 10:41 صبح
منظور من هم همین بود ولی مثل اینکه درست منظورم رو نرسوندم ، خوب معلومه که اشکال از Free هست چون شئ ساخته نشده که بخواد آزاد بشه .
اما منظور تو واضح بود :

پیغام خطا AV میده ، دلیلش این هست که کلاس TStringList به طور پیش فرض با nil مقدار دهی نشده و وقتی شما با تابع Assigned چکش میکنید در حقیقت شیئی که هیچ اشاره گری در حافظه براش در نظر گرفته نشده رو به تابع Assigned ارجاع دادید و تابع آدرس حافظه ای که در محدوده دسترسی برنامه نیست رو چک میکنه و خطای AV رخ میده .
اشاره گر در نظر گرفته شده ...

کار این دو تابع این هست که میگن آرایه از چه خانه ای شروع و به چه خانه ای ختم میشه ، همین .
تصحیح می کنم ! ( اشتباه کردم :متفکر: ) : برای عناصری از یک آرایه ی Dynamic که اشاره گری در حافظه دارند ...

چرا لازم به استفاده از تابع Assigned نیست ؟
وجود Assigned برای Free کردن یک عنصر از آرایه که برابر Nil قرار نگرفته ، با نبودش فرقی نمی کنه ، Assigned مقادیر برابر Nil و غیر Nil ! رو بررسی می کنه ...

اگه از FreeAndNil استفاده بشه دیگه نیازی نیست ، FreeAndNil ابتدا اشاره گر شیء رو برابر Nil قرار میده و بعد اون رو Free میکنه ، متد Free هم ابتدا چک می کنه که آدرس شیء Nil هست یا نه و اگه برابر Nil نبود ، اون رو Destroy می کنه ...
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;
Temp.Free;
end;

procedure TObject.Free;
begin
if Self <> nil then
Destroy;
end;

وقتی شیء ای Nil نباشه با فراخوانی Free دستور Destroy هم فراخوانی میشه و شیء ای که Create نشده نمی تونه Destroy بشه ! ، پس این درست نیست :

وقتی شیئی وجود خارجی نداره چه طور به وسیله تابع Assigned میخواین بررسی کنیدش ؟
تابع Assigned اشاره گر مربوط به یک شئ رو چک میکنه که آیا به جایی اشاره داره یا نه .

در ضمن با استفاده از متد Free یک کلاس شئ آزاد میشه و دیگه اشاره گری بهش اشاره نمیکنه پس یعد از آزاد سازی اگر با تابع Assgined شئ رو به صورت زیر چک کنیم با پیغام خطا Invalid Pointer مواجه میشیم :

موفق باشی ...

Mahmood_M
چهارشنبه 29 اردیبهشت 1389, 11:02 صبح
طبق کد باید شئ TStringList یکی در میون ساخته بشه ولی دیباگش کن ببین چی ساخته شده !
این به خاطر همونیه که گفتم ، عناصر آرایه به صورت پیشفرض Nil نیستند و Assigned برای اونها مقدار True بر می گردونه ...

حالا آرایه رو به بخش Var یونیت منتقل کن و دیباگ کن ، درست پر میشه !
متغیرهای Global به صورت پیشفرض Nil هستند ، یا مقداری ندارند ، مثلا یک متغیر Integer رو اگر به صورت Global تعریف کنی به صورت پیشفرض 0 هست ولی اگه به صورت Local تعریف بشه مقدار اولیش میشه 4872468 !

Felony
چهارشنبه 29 اردیبهشت 1389, 11:08 صبح
اما منظور تو واضح بود :

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


اگه از FreeAndNil استفاده بشه دیگه نیازی نیست ، FreeAndNil ابتدا اشاره گر شیء رو برابر Nil قرار میده و بعد اون رو Free میکنه ، متد Free هم ابتدا چک می کنه که آدرس شیء Nil هست یا نه و اگه برابر Nil نبود ، اون رو Destroy می کنه ...

درسته حواسم به این مورد نبود .