PDA

View Full Version : سوال: چطور میشه یه آرایه با نوع تعریف شده توسط کاربر رو با مقدار یه آرایه دیگه از همون نوع مقدار بدیم؟



mbshareat
چهارشنبه 21 تیر 1391, 21:59 عصر
سلام
نمی دونم اصطلاح متغیری که به صورت Record= تعریف میشه چیه؟
من یه آرایه دارم که از چنین نوعی هست:

Type ItemData=Record
Str:String[150];
FileNo:Word;
PageNo:Word;
Byte:Word;
End;


و به این شکل تعریف شده:
ListItem:Array[0..20000] Of ItemData;

حالا میخوام یه آرایه دیگه رو با همون نوع داشته باشم و بعضی عناصر آیه رو از ListItem بهش انتساب بدم:
NewItem:Array[0..1000] Of ItemData;
سوالم اینه که مثلا اگه بخوام مقدار [ListItem[1 رو به [NewItem[1 انتساب بدم، راه بهینه ای بدون انتساب تک تک فیلها هست یا نه؟
ظاهرا راهش GetMem باشه ولی من روشش رو بلد نیستم.اگه ممکنه یادم بدین.
غیر از بهینه شدن ممکنه بعدا بخوام فیلدهای دیگه ای به این نوع داده اضافه کنم که نمیخوام حتما برم جایی که مقادیر رو از ListItem به NewItem میدم کد رو برای فیلدهای جدید اضافه کنم.
بنابر این اگه یه پروسیجر باشه که یه آیتم از ListItem رو به NewItem انتساب بده کارم راحت تر میشه.
به نظرم تبادل داده بین دو متغیر از دو نوع با طول همسان هم با همین روش عملی میشه.
اگه کسی از دوستان میتونه کمک کنه لطفا دریغ نکنه.

Felony
چهارشنبه 21 تیر 1391, 23:00 عصر
سوالم اینه که مثلا اگه بخوام مقدار[ListItem[1 رو به [NewItem[1 انتساب بدم، راه بهینه ای بدون انتساب تک تک فیلها هست یا نه؟
NewItem[1] := ListItem[1];
منظورتون همین بود ؟!

Ananas
چهارشنبه 21 تیر 1391, 23:34 عصر
سلام.

سوالم اینه که مثلا اگه بخوام مقدار
[ListItem[1 رو به [NewItem[1 انتساب بدم، راه بهینه ای بدون انتساب تک تک فیلها هست یا نه؟
ظاهرا راهش GetMem باشه ولی من روشش رو بلد نیستم.اگه ممکنه یادم بدین.
راهش که همون انتساب دستیه که آقا فرمودن ولی برای کپی کردن یه قسمت از حافظه به قسمت دیگه می تونی از تابع CopyMemory استفاده کنی و یا بایت - بایت از یکی کپی کنی به اون یکی که تابع CopyMemory هم همین کارو میکنه. در واقع GetMem رو وقتی لازم داری که رکورد رو به شکل متغیر استفاده نکنی و به شکل اشاره گر استفاده کنی و اینجا لازمه که خودت دستی حافظه بهش بدی وگر نه خود تعریف متغری از نوع رکوردتون حافظه بهش داده میشه. مثلا اگه بنویسی :

pid : ^ItemData;

دیگه خود به خود حافظه نداره شما باید با GetMem یا همچین چیزی حافظه براش بگیری ولی اگه بنویسی :

id : ItemData;

دیگه خودش اتوماتیکی حافظه میگیره.

mbshareat
پنج شنبه 22 تیر 1391, 11:01 صبح
سلام
آقای Mahan-1363 ممنون.نمی دونم چرا فکر می کردم چنین انتسابی خطا ایجاد می کنه؟ چون دو آرایه در یک نقطه تعریف نشدن.
یادمه وقتی با رنگهای بیت مپ کار می کردم این مشکل رو داشتم.وقتی که میخواستم با ماسک کار کنم و یه متغیر از نوع RGB رو به عنصری از آرایه ای از PRGBArray انتساب بدم.
می بخشین اسم نوع داده ای که کاربر تعریف می کنه چیه؟
بقیه سوالام مستقیم مرتبط با عنوان تاپیک نیست ولی اگه ممکنه جواب بدین.
آقا میشه برای تبادل مقدار بین دو متغیر با سایز یکسان از دو نوع مختلف، کد بذارین؟مثلا دو کارکتر داریم که از فایل خوندیم چطور به متغیری از نوع SmallInt پاس بدیم؟
آیا میشه از فایل بدون نوع ابتداءً داده از نوع Integer گرفت؟

Felony
پنج شنبه 22 تیر 1391, 11:55 صبح
می بخشین اسم نوع داده ای که کاربر تعریف می کنه چیه؟
User defined data type یا user type .


آقا میشه برای تبادل مقدار بین دو متغیر با سایز یکسان از دو نوع مختلف، کد بذارین؟مثلا دو کارکتر داریم که از فایل خوندیم چطور به متغیری از نوع SmallInt پاس بدیم؟
اگر نوع داده ها از یک جنس باشه ولی سایز ( Range ) نوع داده ای یکی نباشه ممکنه مقداری از داده ها از بین بره ، مثلا انتصاب یک متغییر integer به Byte .
ولی وقتی نوع داده ای کلا با هم فرق دارن ( مقل مثال شما که یکی کاراکتر و یکی Smallint هست ) نمیشه به هم انتصابشون داد مگر با پیاده سازی ها خاصی که خودمون میکنیم ، مثلا برای انتصاب یک کاراکتر به یک متغییر SmallInt میشه کد اسکی کاراکتر رو در متغییر SmallInt ذخیره کرد :

var
A: Char;
B: SmallInt;
begin
A:= 'a';
B:= ord(a);
ShowMessage(IntToStr(b));
end;

یا کد زیر که با cast کردن ، کارکتر به صورت خودکار به کد اسکی تبدیل و در داخل متغییر SmallInt ذخیره میشه :

var
A: Char;
B: SmallInt;
begin
A:= 'a';
B:= integer(a);
ShowMessage(IntToStr(b));
end;


آیا میشه از فایل بدون نوع ابتداءً داده از نوع Integer گرفت؟
منظورتون از بدون نوع یعنی فایل هایی که Typed Files نیستن ؟

mbshareat
پنج شنبه 22 تیر 1391, 17:30 عصر
سلام
البته منظور من خواندن دوتا بایت به عنوان SmallInt هستش که هردو دوبایتی هستند.

منظورتون از بدون نوع یعنی فایل هایی که Typed Files نیستن ؟
منظورم چنین چیزیه: F:File; نمی دونم اسمی هم داره یا نه؟

Ananas
پنج شنبه 22 تیر 1391, 21:52 عصر
سلام دوباره. خوب من فکر میکنم منظور آقای شریعت اینه که ما بیایم یک قسمت از حافظه رو به عنوان یک نوع دیگه استفاده کنیم. مثلا ما یک متغیر از نوع اعشاری 32 بیتی داریم که حالا می خوایم اطلاعات اون رو در قالب یک DWORD داشته باشی، کپی کنیم و یا دست کاری کنیم. راه حل، استفاده از آدرش و اشاره گره هست مثلا به شکل زیر :

procedure TForm1.Edit1Change(Sender: TObject);
var
float_32bit : Single;
dword_32bit : DWORD;
begin
float_32bit := StrToFloatDef((Sender as TEdit).Text, 0);
dword_32bit := (PDWORD(@float_32bit))^;
Label1.Caption := FloatToStr(float_32bit);
Label2.Caption := IntToHex(dword_32bit, 8);
end;

و یا مثلا :

procedure TForm1.Edit1Change(Sender: TObject);
var
float_32bit : Single;
byte_8bit : Byte;
I: Integer;
s : string;
begin
float_32bit := StrToFloatDef((Sender as TEdit).Text, 0);
Label1.Caption := FloatToStr(float_32bit);
s := '0x' + IntToHex( (PDWORD(@float_32bit))^, 8) + #13#10;
for I := 0 to 3 do
begin
byte_8bit := (PByte(UInt64(@float_32bit) + I))^;
s := s + IntToHex(byte_8bit, 2) + ' ';
end;
Label2.Caption := s;
end;

SAASTN
جمعه 23 تیر 1391, 19:59 عصر
نمی دونم اصطلاح متغیری که به صورت Record= تعریف میشه چیه؟
اون چیزی که بصورت = record تعریف میشه، اگه تو بخش type باشه، نوع داده ای هست نه متغیر. به این نوع "نوع داده" هم بصورت ساده همون رکورد میگن. متغیری هم که از این نوع تعریف میشه همون متغیره و اگه بخواین دقیق تر بگین همون "متغیر از نوع فلان" میشه.

و یه سری توضیحات احتمالا اضافی:
اگه بخوای یه آرایه رو کلا توی یه آرایه دیگه کپی کنی، اگه آرایه داینامیک باشه خیلی ساده از متد Copy استفاده میشه، و اگه آرایه استاتیک باشه می شه از CopyMemory استفاده کرد:
type
TMyRecord = record
Field1: LongInt;
Field2: ShortString;
end;
var
DAry1, DAry2: array of TMyRecord;
Ary1, Ary2: array [0..999] of TMyRecord;
I: Integer;
begin
SetLength(DAry1, 1000);
for I := 0 to 999 do
begin
Ary1[I].Field1 := I;
Ary1[I].Field2 := '#'+IntToStr(I);

DAry1[I].Field1 := I;
DAry1[I].Field2 := '#'+IntToStr(I);
end;
CopyMemory(@Ary2, @Ary1, SizeOF(Ary1));

DAry2 := Copy(DAry1);
end;

حالا اگه بخوای یه بخش از آرایه اول رو بصورت بلوکی تو آرایه دوم کپی کنی اینطوری میشه:
CopyMemory(
Pointer(LongWord(@Ary2) + 200 * SizeOf(TMyRecord)),
Pointer(LongWord(@Ary1) + 100 * SizeOf(TMyRecord)),
50 * SizeOf(TMyRecord));

این کد، درایه های 100 تا 150 آرایه Ary1 رو توی درایه های 200 تا 250 آرایه Ary2 کپی میکنه. فقط باید توجه داشت که این کا رو به هیچ عنوان نمیشه با آرایه داینامیک انجام داد. چون توی آرایه های داینامیک، درایه ها لزوما توی حافظه های مجاور هم قرار ندارن و ممکنه جدا از هم ذخیره شده باشن، یه چیزی مثل لیست های پیوندی.

به نظرم تبادل داده بین دو متغیر از دو نوع با طول همسان هم با همین روش عملی میشه.
اگه مطمئن هستید که دو نوع داده ای کاملا متناظر هستند، این کار با یه TypeCast معمولی شدنیه، مثل:
type
TRect1 = record
Left, Top, Right, Bottom: Integer;
end;
TRect2 = record
LeftTop, RightBottom: TPoint;
end;

procedure TForm1.Button4Click(Sender: TObject);
var
Rect1: TRect1;
Rect2: TRect2;
begin
Rect2 := TRect2(Rect1);
end;

اما توی چنین شرایطی اگه تعریف TRect1 و TRect2 دست خودمون باشه، راه درست تر استفاده از رکورد با فیلدهای متغیره:
TRect = record
case Integer of
0: (Left, Top, Right, Bottom: Longint);
1: (TopLeft, BottomRight: TPoint);
end;

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

آقا میشه برای تبادل مقدار بین دو متغیر با سایز یکسان از دو نوع مختلف، کد بذارین؟مثلا دو کارکتر داریم که از فایل خوندیم چطور به متغیری از نوع SmallInt پاس بدیم؟
var
B1, B2: Byte;
I: SmallInt;
begin
B1 := $11;
B2 := $22;
I := B1 + (B2 shl 8);
end;

mbshareat
شنبه 24 تیر 1391, 12:18 عصر
سلام بر دوستان
اگه ممکنه در مورد این کد توضیح بدین:
TRect = record
case Integer of
0: (Left, Top, Right, Bottom: Longint);
1: (TopLeft, BottomRight: TPoint);
end;
بارها چنین کدی رو دیدم و نفهمیدم تعیین حالت (Case ) چطور با تعریف سازگاره!؟
اگه بخوایم استفاده کنیم اینطور میشه؟
Var
R:TRect;
Begin
R.Left:=200;
R.Top:=100;
R.BottomRight:=Point(300,200);
Canvas.Rectangle(R);
End;

Ananas
شنبه 24 تیر 1391, 13:08 عصر
در مورد union تو C++‎ اطلاع داری؟ اینم همونجوریه. از یک قسمت حافظه به عنوان چند نوع مختلف که سایزشون در مجموع یکی باشه میشه دسترسی پیدا کرد. میشه گفت نحوه ی دسترسی به داده های record رو به چند روش تعریف میکنی. یعنی با هر case یک روش دسترسی به بایت های record رو مشخص میکنی. مثلا همین TRect رو می خوای به دو روش استفاده کنی که یکی به شکل 4 تا تک عدد و یکی به شکل دو تا Point. و شما برای استفاده از هر case کاری به 0 و 1 و 2 و ... نداری و از همون اسامی که براش انتخاب شده استفاده میکنی. موقع تعریف هم باید سایز case ها با هم برابر باشه و بهتره که اینجور موقع ها برای اینکه بین داده ها بایت اضافی قرار نگیره (مثلا به دلیل بخش پذیر نبودن به 4) بهتره از عبارت packed استفاده بشه و یا دایرکتیو {$A1} و یا هر چیزی که مناسبش باشه. مثلا :

type
TVec3D = packed record
case Integer of
0:
(
x, y, z: Single;
);
1:
(
v: array [0 .. 2] of Single;
);
end;


اینجا هم به شکل آرایه برای استفاده در حلقه و هم به شکل اسم x y z میتونید به عناصر بردار دسترسی داشته باشید. ببخشید مثال بالا رو تو این سایت زیاد نوشتم (فوشکشمون نکنید)
و یا :

UInt128Rec = packed record
case Integer of
0:
(
i_64 : array [0..1] of UInt64;
);
1:
(
i_32 : array [0 .. 3] of UInt32;
);
2:
(
i_16 : array [0 .. 7] of UInt16;
);
3:
(
i_8 : array [0 .. 15] of UInt8;
);
end;

این مثال هم 128 بیت رو ذخیره میکنه که با توجه به اسمی که بعد از اسم متغیر و '.' می نویسیم تعیین میشه که کدوم بایت رو بخونه یا بنویسه. یعنی دقیقا همون چیزی که می گفتید در مورد استفاده از یک قسمت از حافظه به عنوان انواع مختلف.

Ananas
شنبه 24 تیر 1391, 13:39 عصر
و اما یک سوال هم خودم دارم که تو یک تاپیک یکی از دوستان در مورد سخت افزار های مختلف گفتن که ممکنه بایت ها رو برعکس بخونه و تو یک سخت افزار ممکنه استفاده از union و همین روش در دلفی، با سخت افزار دیگه نتیجش جابجا بشه یعنی مثلا یک DWORD رو مقدار بدیم ولی در بایت ها نتیجه برعکس بشه. من هنوز هم به صحت این موضوع مطمئن نیستم چون خیلی از برنامه ها به مشکل بر می خوره. من به نظرم میاد که اون سخت افزار که بایت ها رو معکوس می خونه و می نویسه، در مورد union هم طوری معکوس میشه که نتیجه بازم یکی میشه (یعنی همون بلایی که سر DWORD میاره همون بلا رو هم سر آرایه ای 4 تایی از بایت ها میاره. البته این انتظار من از سخت افزاره و نمی دونم واقعا برنامه این خطا رو میکنه یا نه) ولی من این دو مدل سخت افزار رو ندارم که امتحان کنم. اگه کسی در دسترسش هست لطفا امتحان کنه نتیجه رو بگه.
تاپیک مذکور :
http://barnamenevis.org/showthread.php?349249-%D9%85%D9%82%D8%A7%D8%AF%DB%8C%D8%B1-Ch-%D8%A8%D8%B9%D8%AF-%D8%A7%D8%B2-%D8%A7%D8%AC%D8%B1%D8%A7%DB%8C-%D8%AF%D8%B3%D8%AA%D9%88%D8%B1%D8%A7%D8%AA-%D8%B2%DB%8C%D8%B1-%DA%A9%D8%AF%D8%A7%D9%85-%D8%A7%D8%B3%D8%AA%D8%9F