Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Динамические массивы


Страницы:   1 2

DeadMeat ©   (2008-11-21 13:58:00) 

Здравсте.
Есть вопрос по поводу динамических массивов.
Представим, что у нас есть два динамических массива, такого вида:
A1: array of byte;
A2: array of single;
Задача состоит в том, чтобы передав их в определенную процедуру, изменить их длинну и "вернуть назад".
Т.е. нужна некая процедура, которая принимает на вход динамические массивы любого типа, либо поинтер на них, либо еще что. Результатом ее действия должен быть увеличенный на N элементов (или байт, если по другому не получится) переданный ранее массив.
Нечто вроде:
procedure Reallocate(....; const ElementSize: integer);
begin
 .... // увеличение длинны массива на ElementSize
end;
Если я правильно понял, то передать любой массив можно через Open Arrays, но по поводу них справка четко говорит, что менять его длинну в процедуре нельзя.
Пробовал передать просто поинтер, выделить в нем память (GetMem) размером с ElementSize байтов, скопировать в новое место данные из старого (типа того, что делает SetLength) и вернуть новый поинтер на место первого, но память выделяется не понятно как. Т.е. смотрю в дебагер после этих действий и вижу, что на месте этого массива получился всякий мусор. Не в том смысле, что там данные "левые", а в том, что.... Даже не знаю как объяснить. Ну допустим я выделил (точнее хотел выделить) 10 элементов, каждый по 720 байт (нечто типа array of TMyRecord, размер которого 720 байт). В результате в дебагере вижу, что первые два элемента выделились, другие два - нет и т.п. "фигня".
Вообщем суть вопроса. Как сделать так, чтобы в процедуру можно было передать динамический массив любого типа, изменить его размер и "вернуть назад", т.е. чтобы по выходу из этой процедуры, этим массивом можно было пользоваться, записывая данные в его "новые" места.


Sapersky   (2008-11-21 16:35:00) [21]

Кстати о менеджерах памяти. При наличии FastMM не обязательно оптимизировать наращивание массива, можно тупо писать SetLength(Arr, Length(Arr) + 1) :)
Все оптимизации делает сам менеджер.
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1226920476&n=0


Сергей М.   (2008-11-21 16:22:00) [22]


> DeadMeat   (21.11.08 15:49) [13]


Ну а зачем вообще внутри ф-ции, явновзаимодействующей с мкнеджером пямяти, использовать манипуляции с дин.массивами ?


Sapersky   (2008-11-21 16:17:00) [23]

Вот собсна, только благодаря Вашему примеру, я про не узнал. Большое спасибо. Проблема стала почти решена.

Там и увеличение размера есть (Arr_Grow). Правда, не насколько-то, а сразу в 2 раза, но это легко изменить.

Ну по крайней мере, я не нашел способа как ее применить конкретно в этой ситуации...
Признаю, что наверняка плохо искал..
Есть ли таковой?


Ну можно использовать и SetLength, если откастить массив к array of Byte, но это "некрасивый" метод, и при наличии в массиве длинных строк и т.п. managed-типов можно огрести глюков.
И кстати, SetLength для массива преобразуется компилятором в DynArraySetLength с подстановкой нужного типа, так что в любом случае мы используем DynArraySetLength.


DeadMeat   (2008-11-21 16:07:00) [24]


> Плохиш ©   (21.11.08 15:59) [14]

Ну по крайней мере, я не нашел способа как ее применить конкретно в этой ситуации...
Признаю, что наверняка плохо искал..
Есть ли таковой?


Плохиш   (2008-11-21 15:59:00) [25]


> Sapersky   (21.11.08 15:44) [12]
>
> Есть внутренняя функция DynArraySetLength,

Чем "невнутренняя" функция, озвученная в [2] не нравиться?


DeadMeat   (2008-11-21 15:49:00) [26]


> Sapersky   (21.11.08 15:44) [12]

Вот собсна, только благодаря Вашему примеру, я про не узнал. Большое спасибо. Проблема стала почти решена.


> Сергей М. ©   (21.11.08 15:33) [10]
> Amoeba ©   (21.11.08 15:36) [11]

Аййй.... больно... но не смертельно.. )) Как бы выяснить, что конкретно там не верно?


Sapersky   (2008-11-21 15:44:00) [27]

Есть внутренняя функция DynArraySetLength, которая задаёт размер дин. массива независимо от типа. Начиная с D6 её "легализовали", т.е. вынесли в interface system.pas (хотя при желании её можно использовать и в более ранних версиях - см. исходник по ссылке).
TypeInfo получаем как TypeInfo(тип массива).


Amoeba   (2008-11-21 15:36:00) [28]


> Вроде работает, но гложат меня сомнения, что я гдето либо
> теряю память, либо вообще все делаю не так.
>

Верно последнее: все делаешь не так.


Сергей М.   (2008-11-21 15:33:00) [29]


> Не покажу


Стыдно чтоль стало ?

И ведь судя по коду в [9] есть за что - замесил в одну кучу и прямую работу с менеджером и дин.массивы ..


DeadMeat   (2008-11-21 15:17:00) [30]


> Сергей М. ©   (21.11.08 14:31) [6]

Не покажу... ))))
На самом деле я столько экспериментировал, чтобы получилось без извращений, что щас уже и не восстановлю все.
Сейчас сделал так:

type
 TMyRecord = record
   public
     var
       Data: integer;
       NewData: word;
       AnotherData: single;

     procedure Init(const Val: integer);
 end;
.....
{ TMyRecord }

procedure TMyRecord.Init(const Val: integer);
begin
 Data        := Val + 0;
 NewData     := Val + 1;
 AnotherData := Val + 2;
end;
.....
function Reallocate(const Buf: pointer; const Count, ElementSize: integer): pointer;
type
 PByteArray = ^TByteArray;
 TByteArray = array of byte;
var
 bufData: array of byte;
 bufRelocArray: PByteArray;
begin
 SetLength(bufData, Count * ElementSize);
 MoveMemory(@bufData[0], Buf, Count * ElementSize);

 New(bufRelocArray);
 SetLength(bufRelocArray^, Count + 1);
 MoveMemory(@bufRelocArray^[0], @bufData[0], Count * ElementSize);
 Result := bufRelocArray^;
end;
.....
var
 Buffer: array of TMyRecord;
begin
 SetLength(Buffer, 1);
 Buffer[0].Init(1);

 Buffer := Reallocate(Buffer, Length(Buffer), SizeOf(TMyRecord));
 Buffer[1].Init(2);

 Buffer := Reallocate(Buffer, Length(Buffer), SizeOf(TMyRecord));
 Buffer[2].Init(3);
end;
.....

Вроде работает, но гложат меня сомнения, что я гдето либо теряю память, либо вообще все делаю не так.


> Anatoly Podgoretsky ©   (21.11.08 14:54) [7]

Можем считать, что я вернулся в школу.. ;))


> Sapersky   (21.11.08 15:01) [8]

Пасиба.. обязательно посмотрю.


Sapersky   (2008-11-21 15:01:00) [31]

http://sapersky.narod.ru/files/Arrays.rar


Anatoly Podgoretsky   (2008-11-21 14:54:00) [32]

> DeadMeat  (21.11.2008 13:58:00)  [0]

Ты вроде в школе не учишься, а задание школьное или все таки учишься?


Сергей М.   (2008-11-21 14:31:00) [33]


> вернуть новый поинтер на место первого, но память выделяется
> не понятно как


Показывай код ..


Сергей М.   (2008-11-21 14:29:00) [34]


> Как сделать так, чтобы в процедуру можно было передать динамический
> массив любого типа


Любого не получится - тип должен быть известен и вызывающей и вызываемой процедуре.


Плохиш   (2008-11-21 14:22:00) [35]


> DeadMeat   (21.11.08 13:58)

Open Array и Dinamic Array две разные сущности и имеют общее только одно слово в названии...


DeadMeat   (2008-11-21 14:19:00) [36]


> tesseract ©   (21.11.08 14:00) [1]

Не совсем понял как это. Делал варианты типа:
procedure Reallocate(Buf: array of const);
procedure Reallocate(var Buf: array of const);
procedure Reallocate(const Buf: array of const);
Даже делал реальный тип массива, который передаю (array of byte пробовал).
Все равно на строке SetLength(Buf, 10) выдает "Incompatible types".


{RASkov}   (2008-11-21 14:18:00) [37]

А вот прямо просто SetLength не подойдет разве?


tesseract   (2008-11-21 14:00:00) [38]

Драсте вам, передавай ссылку и размер массива в процедуру. Всё выйдет.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо