Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.10.21;
Скачать: CL | DM;

Вниз

Унифицированный способ сравнивать массивы?   Найти похожие ветки 

 
alex_ant ©   (2007-09-30 17:15) [0]

Пишу тесты модулей, часто возникает необходимость сравнивать два динамических массива на идентичность. Пока что тупо сравниваю поэлементно. Можно ли в Delphi реализовать некую функцию, которая бы сравнивала два массива на идентичность, вне зависимости от типа содержащихся в них элементов, чтобы можно было эту функцию использовать и для сравнения массивов строк, массивом чисел и т. д.?

К примеру, в Perl существует возможность сравнить массивы любого типа на идентичность, передав ссылки на них в качестве параметра в одну унифицированную функцию. Далее функция сама выясняет их типизацию и размерность, и возвращает истину, если количество элементов и их тип и значение совпадают. Можно ли так же в Delphi сделать?

Заранее благодарю за советы.


 
alex_ant ©   (2007-09-30 17:23) [1]

Понял тут, что вопрос фактически является вопросом о возможности сравнить переменную любого типа (объект, массив, запись и пр.) с любой другой переменной...

Типа

if MegaEqual(PVarA, PVarB: Pointer) then
 ShowMessage("Переменные равны");
else
 ShowMessage("Переменные не равны");

где PVarA, PVarB — указатели на переменные любого типа.

P. S. Не судите строго, если что-то не так, с указателями работал очень мало.


 
Dib@zol ©   (2007-09-30 17:25) [2]

В принципе да, если в каждом массиве переменные идут последовательно. Тогда их можно представить как два здоровенных массива байт и сравнивать побайтно...


 
alex_ant ©   (2007-09-30 17:36) [3]


> В принципе да, если в каждом массиве переменные идут последовательно.
>  Тогда их можно представить как два здоровенных массива
> байт и сравнивать побайтно...
>


А как это можно сделать? Можете показать небольшой пример?


 
tesseract ©   (2007-09-30 17:48) [4]

Xor по размеру массива?


 
Dib@zol ©   (2007-09-30 17:52) [5]

Хз. Вот щас только что написал. Не тестировал, но теоретически должно сработать. Len - это длина большего из массивов. Находится с помощью length(Массив). Через Пойнтер её не получить. А, да - если один из массивов короче чем Len, то либо возникнет AV, либо продолжение массива будет случайным образом браться из памяти.

function MegaCompare(A, B : Pointer; Len:Cardinal):boolean;
var
 b1, b2 : Byte;
 i, k : Cardinal;
begin
 Result:=true;
 k:=Len-1;
 for i:=0 to k do begin
   CopyMemory(@b1, Pointer(longInt(A)+i), 1);
   CopyMemory(@b2, Pointer(longInt(B)+i), 1);
   if b1<>b2 then begin
     Result:=false;
     break;
   end;
 end;
end;


 
vpbar ©   (2007-09-30 17:57) [6]

procedure TForm1.Button1Click(Sender: TObject);

function Сompare(a,b:pointer;sizeOfElement:byte):Boolean;
var La,Lb,j:integer;
   ca,cb:Pchar;
begin
result:=false;
if (a=nil)or(b=nil)then exit;
La:=PInteger(Integer(a)-4)^*sizeOfElement;
Lb:=PInteger(Integer(b)-4)^*sizeOfElement;
if La<>Lb then exit;
Ca:=Pchar(a);
Cb:=Pchar(b);
result:=CompareMem(a,b,La)
end;

var x,y:array of byte;
i:integer;
begin
SetLength(x,3);
for i:=low(x) to High(x) do  x[i]:=(i+1);
SetLength(y,3);
for i:=low(y) to High(y) do  y[i]:=(i+1);
//y[2]:=5;

if compare(x,y,sizeof(x[666])) then
caption:="Равны" else Caption:="Не равны";
end;

compare - сравнивает два динамических массива (можно и строки если вызывать так compare(@s1[1],@s2[1],1)) тип массива должен быть одинаковый. Если элементы массива - суть ссылки на объекты (строки, классы), то естественно не работает.


 
vpbar ©   (2007-09-30 17:59) [7]

>>Dib@zol ©   (30.09.07 17:52) [5]
>>Через Пойнтер её не получить.
Гы. А я получил. Вот только размер и тип елемента никак (точнее сложно) ибо он известен только при компиляции.


 
vpbar ©   (2007-09-30 18:05) [8]

Dib@zol ©   (30.09.07 17:52) [5]
кстати ваш вариант проще сделать так
function MegaCompare(A, B : Pointer; Len:Cardinal):boolean;
begin
result:=CompareMem(a,b,Len);
end;


 
Dib@zol ©   (2007-09-30 18:07) [9]

> Гы. А я получил.

Ну и как же? А? Ведь что такое Pointer? Это ссылка на начало (первый байт) блока данных в адресном пространстве проги. И длиться этот блок может хоть до $7FFFFFFF. Так что ты не прав. Допустим есть у нас "голое" содержимое RAM. И есть первый байт (выделен). И как узнать какой байт является последним?

-d FFF2:93F1
FFF2:93F0     BF 5C 00 8A 1C F3 A4-33 C0 AB AB 59 5E 1F 1E    .\.....3...Y^..
FFF2:9400  56 C5 74 0A 8A 3C F3 A4-AB AB 5E 1F C5 74 02 80   V.t..<....^..t..
FFF2:9410  C9 80 8B F9 F3 A4 FE C9-8A C7 32 FF E8 A7 0C 73   ..........2....s
FFF2:9420  02 8A F9 8A C3 32 DB E8-9C 0C 73 02 8A D9 E8 36   .....2....s....6
FFF2:9430  A4 66 FF 74 12 66 FF 74-12 66 26 8F 06 0A 00 33   .f.t.f.t.f&....3
FFF2:9440  C0 8E D8 66 8F 06 88 00-36 C7 06 2C 03 80 00 36   ...f....6..,...6
FFF2:9450  8E 1E 30 03 36 8C 1E 2E-03 F6 46 FB 01 74 27 36   ..0.6.....F..t"6
FFF2:9460  C5 36 BF 0E C4 7E FC 26-8C 5D 10 4E 4E 89 1C 26   .6...~.&.].NN..&
FFF2:9470  89                                                .


 
Dib@zol ©   (2007-09-30 18:13) [10]

> result:=CompareMem(a,b,Len);

Хмм. А вот и решение! Ну ладно, будем считать, что у меня просто показан принцип...


 
vpbar ©   (2007-09-30 18:21) [11]

Dib@zol ©   (30.09.07 18:07) [9]
запусти код из [6] . Работает? Хотя в Сompare длина массивов не передается. Истина проверяется практикой (с) Классик.
А по поводу. "Ну и как же?" Посмотри что такое динамический массив и строка. Это адрес блока. А четыре байта перед указателем - это длина блока. (Строка еще нулем заканчивается).
"Ведь что такое Pointer? " -Pointer - это Указатель(Pointer по англ). Т.е. вещь в себе. Pointer - это четыре байта в которых должен содержаться адрес в памяти. А что там по этому адресу - это только творцу(программеру) известно. Может массив, а может объект.


 
Dib@zol ©   (2007-09-30 18:37) [12]

> [11] vpbar ©   (30.09.07 18:21)

Через указатель-Pointer-адрес длину получить невозможно, за исключением тех случаев, когда это предусмотрено структурой хранящегося в памяти объекта, на которого поинтер указывает. Все довольны?


 
Anatoly Podgoretsky ©   (2007-09-30 18:41) [13]

> Dib@zol  (30.09.2007 18:37:12)  [12]

Нет, поскольку нет никаких методов подтвердить, что указатель указывает на подобную структуру.


 
vpbar ©   (2007-09-30 19:00) [14]

Dib@zol ©   (30.09.07 18:37) [12]
Ага. Именно так. Доволен. Приятно что собеседник умен.

Anatoly Podgoretsky ©   (30.09.07 18:41) [13]
ну в данном случае оба решения нетипобезопастны. И типобезопастных я не вижу. Это в дотнете наверно можно, а в делфи вряд ли.


 
alex_ant ©   (2007-09-30 19:08) [15]

Огромное спасибо вам за советы. Попробовал такой код:


var
 PA, PB: Pointer;
 A, B: array of string;
begin
 SetLength(A, 2);
 A[0] := "1";
 A[1] := "2";
 SetLength(B, 2);
 B[0] := "1";
 B[1] := "2";

 PA := Pointer(A);
 PB := Pointer(B);

 if CompareMem(PA, PB, Length(A)) then
   ShowMessage("Равны")
 else
   ShowMessage("НЕ Равны");


Для массивов Integer работает, для массивов строк — нет.


 
vpbar ©   (2007-09-30 19:09) [16]

>>alex_ant ©   (30.09.07 19:08) [15]
Читал [6] ??
Если элементы массива - суть ссылки на объекты (строки, классы), то естественно не работает.
Или это скрытый вопрос "почему для строк не работает"?


 
alex_ant ©   (2007-09-30 19:29) [17]


> Или это скрытый вопрос "почему для строк не работает"?


:) Да, это был скрытый вопрос. Прошу прощения, не обратил внимания на слово «строки».

В общем, общий вывод, наверное, заключается в том, что проще делать поэлементное сравнение, а Delphi не позволяет «железно» сравнивать переменные неизвестного типа. Эх...


 
vpbar ©   (2007-09-30 19:38) [18]

>>alex_ant ©   (30.09.07 19:29) [17]
Дело в том что в этом (array of string) в массиве хранятся указатели (строка это по сути указатель).
Здесь  
B[0] := "1";
A[0] := "1";
память будет выделятся для каждой строки и следовательно указатели (строки B[0],A[0]) будут разные.
Надеюсь понятно.
В общем случае вывод правильный. В частном случае (массив простых типов) быстрее и проще как я указал или как в [15]. Но в при этом можно по ошибке передать массив не того типа.


 
oxffff ©   (2007-09-30 20:01) [19]


> alex_ant ©   (30.09.07 19:29) [17]
>
> > Или это скрытый вопрос "почему для строк не работает"?
>
>
>
> :) Да, это был скрытый вопрос. Прошу прощения, не обратил
> внимания на слово «строки».
>
> В общем, общий вывод, наверное, заключается в том, что проще
> делать поэлементное сравнение, а Delphi не позволяет «железно»
> сравнивать переменные неизвестного типа. Эх...


TypeInfo?


 
Riply ©   (2007-10-01 06:37) [20]

> [0] alex_ant ©   (30.09.07 17:15)

http://www.rsdn.ru/article/Delphi/dynarrays.xml
P.S.
Если внимательно прочитать эту статью и разобраться, то все получиться :)



Страницы: 1 вся ветка

Текущий архив: 2007.10.21;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.038 c
1-1186651845
tio
2007-08-09 13:30
2007.10.21
Плавающие панели как в Photoshop


1-1186667073
tytus
2007-08-09 17:44
2007.10.21
FastReport 4 как объединить несколько TfrxMemoView?


15-1190638144
Empleado
2007-09-24 16:49
2007.10.21
И почему я - не таракан?!


6-1171203227
Grol
2007-02-11 17:13
2007.10.21
Узнать инфу о компах в сети!


15-1190559516
DDDeN
2007-09-23 18:58
2007.10.21
Средство создания значков