Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2007.10.21;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.173 c
3-1182017847
Kley
2007-06-16 22:17
2007.10.21
Сравнение данных


2-1190714903
zzzz
2007-09-25 14:08
2007.10.21
Узнать редактировался ли столбец


15-1190345728
Riply
2007-09-21 07:35
2007.10.21
Коварный TStrings :)


2-1190817616
Vitek2
2007-09-26 18:40
2007.10.21
Помогите с TabControl!


15-1190118818
Шёлк
2007-09-18 16:33
2007.10.21
Тема о калькуляторе





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский