![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Подскажите функцию [D6, Win2k]
Андрусь © (2002-08-21 12:10:00)Привет всем! Такая вот проблемка:работаю с динамическими массивами,объявленными как
array of ....Есть ли функция удаления i-го элемента массива(память до этого элемента не трогать,а начиная с данного сдвинуть все элементы наsizeof(type))байт влево.Зараннее всем большое спасибо!
Alx2 (2002-08-22 17:08:00) [1]>Андрусь © (22.08.02 15:24)
В твоей ветке про SetLength Ученик дал корректное решение.
А все-таки, если принять во внимание описанную тобоу задачу, лучше использовать списки объектов (или объект-список).
Если жесткая оптимизация - то статические структуры.
Андрусь (2002-08-22 15:24:00) [2]В принципе можно поставить DynArraySetLength,но не очень красиво получится.
Alx2 (2002-08-22 14:10:00) [3]>Только вот что делать с SetLength(..)?
Поэтому и был dummy :(
Андрусь (2002-08-22 12:57:00) [4]А вот так работает:
Var
Source, Dest : Integer;
// DummyArr : array of char absolute Arr;
p_source,p_dest:pointer;
Begin
ArrSize := ArrSize * ElemSize;
Source := (DeleteIdx+1)*ElemSize;
Dest := Source-ElemSize;
p_dest:=Pointer(Integer(Arr)+Dest);
p_source:=Pointer(Integer(Arr)+Source);
Move(p_source^,p_dest^,ArrSize-(DeleteIdx+1)*ElemSize);
SetLength(..);
End;
Только вот что делать с SetLength(..)?
Андрусь (2002-08-22 12:46:00) [5]Что-то вот конструкция
DummyArr : array of char absolute Arr;немного навевает опасения - каков размер этого массива,я посмотрел под дебагером - его размер равен размеру Arr.Видимо придётся делать через указатели.
Alx2 (2002-08-22 11:11:00) [6]Да. Та самая проблема с менеджером памяти.
Надо подумать.
Андрусь (2002-08-22 10:56:00) [7]Пишу вот такой код,один в один сдуваю у тебя - код красивый не спорю,у самого такие же мысли были. НО...На второй месседж выдаёт
такую строку:0,1,2,4634116,12656560,4148,7,8,9.
Procedure TForm1.Delete_Element(Var Arr; ArrSize : Integer; ElemSize, DeleteIdx : Integer);
Var
Source, Dest : Integer;
DummyArr : array of char absolute Arr;
Begin
ArrSize := ArrSize * ElemSize;
Source := (DeleteIdx+1)*ElemSize;
Dest := Source-ElemSize;
Move(DummyArr[Source],DummyArr[Dest],ArrSize-(DeleteIdx+1)*ElemSize);
SetLength(DummyArr,ArrSize div ElemSize - 1);
End;
procedure TForm1.Button1Click(Sender: TObject);
const del=3;
n=10;
var SS:array of integer;i:integer;
procedure ShowArray(s:string);
var j:integer;s1:string;
Begin
s1:="";
For j:=0 To Length(SS)-1 Do
s1:=s1+#10+" a["+IntToStr(j)+"]="+IntToStr(SS[j]);
ShowMessage(s+" удаляли "+IntToStr(del)+#10+s1);
End;
begin
SetLength(SS,n);
For i:=0 To n-1 Do SS[i]:=i;
ShowArray("Begin");
Delete_Element(SS,Length(SS),SizeOf(SS[0]),del);
ShowArray("End");
end;
Alx2 (2002-08-22 08:15:00) [8]>Андрусь © (21.08.02 19:45)
>Что-то не работает
Пример (и не только этот) работает точно.
Напиши что именно не работает. С примером кода.
Андрусь (2002-08-21 19:45:00) [9]Что-то не работает.
Alx2 (2002-08-21 17:04:00) [10]>Андрусь © (21.08.02 15:45)
Получилось именно для динамических массивов.
UniversalDelete(Var Arr; ArrSize : Integer; ElemSize, DeleteIdx : Integer);
Var
Source, Dest : Integer;
DummyArr : array of char absolute Arr;
Begin
ArrSize := ArrSize * ElemSize;
Source := (DeleteIdx+1)*ElemSize;
Dest := Source-ElemSize;
Move(DummyArr[Source],DummyArr[Dest],ArrSize-(DeleteIdx+1)*ElemSize);
SetLength(DummyArr,ArrSize div ElemSize - 1);
End;
Пример использования:
Var
SS : array of integer;
begin
setlength(SS,10);
for k := 0 to 9 do SS[k] := (k);
UniversalDelete(SS,Length(SS),SizeOf(SS[0]),2);
Первый параметр - массив.
Второй - количество элементов в нем
Третий - размер одного элемента массива
Четвертый - номер удаляемого элемента (считая с нуля).
PS.
Будь осторожен. Написано в черновую, хоть глюков пока не замечено (но потенциально может испортить работу менеджера памяти - надо проверить)
Alx2 (2002-08-21 16:02:00) [11]>Андрусь © (21.08.02 15:45)
Что-то у тебя напахано нехорошее. Я имел ввиду следущее:
var a1:TMyrecArray1;a2:TMyrecArray2;
Begin
move(a1[i+1],a1[i],(length(a1)-i-1)*sizeof(a1[i]));
setlength(a1,length(a1)-1);
move(a2[i+1],a2[i],(length(a2)-i-1)*sizeof(a2[i]));
setlength(a2,length(a2)-1);
End;
А реализация с типом variant скорее всего заткнется на пользовательских типах.
Но есть еще идеи:
делаем процедуру Delete_что-то_там, параметром в которую пойдет указатель на твой массив (пусть даже как безтиповая переменная), количество элементов в нем, размер одного элемента. На основании этих данных легко получить искомое :)
Андрусь (2002-08-21 15:45:00) [12]Не понял - поправь мой пример,бо не работает.Тип не разделяется..
Alx2 (2002-08-21 14:33:00) [13]Вот этого хватит на оба случая:
move(a1[i+1],a1[i],(length(a1)-i-1)*sizeof(a1[i]));
setlength(a1,length(a1)-1);
Андрусь (2002-08-21 14:22:00) [14]Всё равно не понял как вариант к Myrec привязать.Как из него тип узнать
typeof(p) не работает.Да и не красиво как-то у меня получается...
Procedure Delete_Element(p:variant; i: integer);
var a1:TMyrecArray1;a2:TMyrecArray2;
Begin
If typeof(p) is TMyrecArray1 Then
Begin
move(a1[i+1],a1[i],(length(a1)-i-1)*sizeof(a1[i]));
setlength(a1,length(a1)-1);
End
Else if typeof(p) is TMyrecArray2 Then
Begin
move(a2[i+1],a2[i],(length(a2)-i-1)*sizeof(a2[i]));
setlength(a2,length(a2)-1);
End;
End;
Alx2 (2002-08-21 14:01:00) [15]>Андрусь © (21.08.02 13:28)
>Хорошо,если у меня array of MyRecord?
Все равно спасет мой вариант без изменений (sizeof(a[i]) даст то, что надо), или тот же Delete.
>Как там вариант использовать,чего-то не доезжаю
см. :
{ Variant type codes (wtypes.h) }
varEmpty = $0000; { vt_empty 0 }
varNull = $0001; { vt_null 1 }
varSmallint = $0002; { vt_i2 2 }
varInteger = $0003; { vt_i4 3 }
varSingle = $0004; { vt_r4 4 }
varDouble = $0005; { vt_r8 5 }
varCurrency = $0006; { vt_cy 6 }
varDate = $0007; { vt_date 7 }
varOleStr = $0008; { vt_bstr 8 }
varDispatch = $0009; { vt_dispatch 9 }
varError = $000A; { vt_error 10 }
varBoolean = $000B; { vt_bool 11 }
varVariant = $000C; { vt_variant 12 }
varUnknown = $000D; { vt_unknown 13 }
//varDecimal = $000E; { vt_decimal 14 } {UNSUPPORTED as of v6.x code base}
//varUndef0F = $000F; { undefined 15 } {UNSUPPORTED per Microsoft}
varShortInt = $0010; { vt_i1 16 }
varByte = $0011; { vt_ui1 17 }
varWord = $0012; { vt_ui2 18 }
varLongWord = $0013; { vt_ui4 19 }
varInt64 = $0014; { vt_i8 20 }
//varWord64 = $0015; { vt_ui8 21 } {UNSUPPORTED as of v6.x code base}
{ if adding new items, update Variants" varLast, BaseTypeMap and OpTypeMap }
varStrArg = $0048; { vt_clsid 72 }
varString = $0100; { Pascal string 256 } {not OLE compatible }
varAny = $0101; { Corba any 257 } {not OLE compatible }
// custom types range from $110 (272) to $7FF (2047)
varTypeMask = $0FFF;
varArray = $2000;
varByRef = $4000;
{ TVarRec.VType values }
vtInteger = 0;
vtBoolean = 1;
vtChar = 2;
vtExtended = 3;
vtString = 4;
vtPointer = 5;
vtPChar = 6;
vtObject = 7;
vtClass = 8;
vtWideChar = 9;
vtPWideChar = 10;
vtAnsiString = 11;
vtCurrency = 12;
vtVariant = 13;
vtInterface = 14;
vtWideString = 15;
vtInt64 = 16;
{ Virtual method table entries }
vmtSelfPtr = -76;
vmtIntfTable = -72;
vmtAutoTable = -68;
vmtInitTable = -64;
vmtTypeInfo = -60;
vmtFieldTable = -56;
vmtMethodTable = -52;
vmtDynamicTable = -48;
vmtClassName = -44;
vmtInstanceSize = -40;
vmtParent = -36;
vmtSafeCallException = -32;
vmtAfterConstruction = -28;
vmtBeforeDestruction = -24;
vmtDispatch = -20;
vmtDefaultHandler = -16;
vmtNewInstance = -12;
vmtFreeInstance = -8;
vmtDestroy = -4;
vmtQueryInterface = 0;
vmtAddRef = 4;
vmtRelease = 8;
vmtCreateObject = 12;
Андрусь (2002-08-21 13:51:00) [16]Как там вариант использовать,чего-то не доезжаю..
Андрусь (2002-08-21 13:28:00) [17]Хорошо,если у меня
array of MyRecord?
Alx2 (2002-08-21 13:09:00) [18]Единственно, как такие массивы передавать в качестве параметра в общую процедуру с сохранением информации о типе?
Думаю, для полноценного решения задачи все-таки подойдет вместо массива тип variant с дальнейшим анализом его содержимого :(
Alx2 (2002-08-21 13:02:00) [19]>Alx2 © (21.08.02 12:57)
Сорри, вот так, конечно
(a[i] as TObject).free или TObject(a[i]).free
Alx2 (2002-08-21 12:57:00) [20]>Андрусь © (21.08.02 12:51)
>Будет ли корректно работать,если элемент - класс.
Будет.
Но если класс, то лучше использовать списки - там все готово.
Иначе до места move(a[i+1],a[i],(length(a)-i-1)*sizeof(a[i])) нужно вызвать a[i].free (если не задумано что-то иное :) ). Но прежде всего нужна проверка на то, что элемент - действительно экземпляр класса.
>Задача,в принципе излагалась уже.Но повторюсь:нужна процедура,
>удаляющая элемент из динамического массива. Словами тип не
>известен,я хотел сказать,что элементами массива являются в
>основном определённые мной типы. Т.е. процедуру пишу сейчас,а
>типы не известны.
Единственная несложная сложность - освобождение памяти, занятой удаляемым из массива элементом (если это нужно, конечно) (см. выше).