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

Вниз

класс и динамический массив   Найти похожие ветки 

 
Alexus12   (2004-04-27 17:04) [0]

Цель - понять как работать с массивом , лежащим в классе

конкретно:
иметь в классе динамический массив пользовательского типа
изменять его размер и добавлять данные методами класса
получать данные по индексу массива (1 элемент, метод showitem ниже) и по выборке (массив элементов, метод find)

Все это я умею, но БЕЗ класса,
а как только в класс встраиваю - глюки лезут!!!
Помогите разобраться с вопросами, приведенными выше!
Больше спасибо!

КОД:

type TStr=string[20];

type TElement
F1:TStr;
F2:TStr;
F3:Integer;
end;

type TmyClass=class
fMas: array of TElement;
Construcot Create;
Procedure Insert(zapis:TElement);
end;

Implementation

Construcot Create;
begin
setlength(fMas,0)
end;

Procedure Insert(zapis:TElement)
begin
setlength(fMas,high(fMas)+1)
fMas[high(fMas)]=zapis;
end;

Procedure TMyclass.ShowItem(i : integer, zapis:TElement);
begin
zapis:=fMas;
end;

А как получить выборку из масссива?
допустим, опишу метод:

Procedure TMyclass.Find(Obraz :TStr);
begin

..здесь переберу массив на предмет равенства поля F1 = Obraz
и сформирую выходной массив-выборку
А вернуть его в вызывающую процедуру как????
Динамический массив в качестве параметра Дельфя использовать не дает!

Результат:
не работает (не изменяется верхняя граница массива)
и периодически лезут exception "AccessViolationError"
причем дебагер выдает только окошко процессора
и не дает посмотреть строку, где произошла ошибка

Что не так и как правильно?


 
Тимохов ©   (2004-04-27 17:07) [1]


> Динамический массив в качестве параметра Дельфя использовать
> не дает!

неопытность не дает, а не дельфи.

опишите в начале модуля
type
  TYourArray = array of TYourElement;

и только име везде и пользуйтесь - в теле модули никаких array of, только TYourArray.


 
Тимохов ©   (2004-04-27 17:09) [2]

и вообще - не фиг разбираться в голове - на это есть комп - набрали текст, хотя бы скомплили, а потом сюда - а то ваш текст даже не компилится.

как-то интереса не вызывает на такую неряшливость отвечать :(


 
Курдль ©   (2004-04-27 17:14) [3]

А можно подробнее, накой? Может быть и мне пригодится, а то я все со списками да коллекциями уродуюсь - так мож массив меня и выручит?


 
Тимохов ©   (2004-04-27 17:17) [4]


>  можно подробнее, накой

автор же сказал - самообразование.


 
Anatoly Podgoretsky ©   (2004-04-27 17:22) [5]

Это не изменяет размер массива setlength(fMas,high(fMas)+1)


 
Alexus12   (2004-04-27 17:52) [6]

>неопытность не дает, а не дельфи

что поделаешь, на своих ошибках...

>текст даже не компилится

большое сорри, постараюсь 8((

>в теле модули никаких array of
то есть нужно вместо определения внутри класса
type TmyClass=class
fMas: array of TElement;
...и далее определение класса..

определить его снаружи:

fMas = array of TElement;

type TmyClass=class
...и далее определение класса..

так?

А как в методе
Procedure TMyclass.Find(Obraz :TStr);
которая получит на входе образец поиска
сформировать выходной массив (выборку из основного)
и передать его (массив) в вызывающую процедуру?
Объявить второй массив глобально (до класса) и работать с ним?

>Это не изменяет размер массива  setlength(fMas,high(fMas)+1)
А как правильно, подскажете?

Большое спасибо за отклики,
это большая приятная неожиданность -
редкий форум так дружелюбен


 
Тимохов ©   (2004-04-27 17:57) [7]

type
  TElement = record ... end;
  TMas = array of TElement;
  TCl = class
     fMas: TMas;
     procedure Add(const aElement: TElement);
     procedure Find(const ...): TMas;
  end

procedure TCl.Add(const aElement: TElement);
begin
  Setlength(fMas, Length(fMas)+1);
  fMas[High(fMas)] := aElement;
end;

procedure TCl.Find(const ...): TMas;
var
  I: Integer;
begin
  Result := nil;
  for I := 0 to High(fMas) do
  begin
     if fMas[I] удовлетворил условию, тогда добавим его в Result:
     Setlength(Result, Length(REsult)+1);
     Result[High(Result)] := fMas[I];
  end;
end;


 
Юрий Зотов ©   (2004-04-27 18:13) [8]

> Alexus12
> Все это я умею, но БЕЗ класса

А классы пишутся так (не проверял, возможны мелкие баги).

type
 TStr = string[20];
 TElement = packed record
   F1: TStr;
   F2: TStr;
   F3: Integer
 end;
 TElementArray = packed array of TElement;

 TElements = class
 private
   FItems: TElementArray;
   function GetCount: Integer;
   function GetItem(Index: Integer): TElement;
   procedure SetItem(Index: Integer; const Value: TElement);
   procedure CheckIndex(Index: Integer);
 public
   destructor Destroy; override;
   procedure Add(const Element: TElement);
   procedure Delete(Index: Integer);
   property Count: Integer read GetCount;
   property Items[Index: Integer]: TElement
     read GetItem write SetItem; default;
 end;

destructor Destroy;
begin
 FItems := nil;
 inherited
end;

procedure CheckIndex(Index: Integer);
begin
 if (Index < 0) or (Index >= Count) then
   raise ERangeError.Create("Item index out of bounds")
end

function GetCount: Integer;
begin
 Result := Length(FItems)
end;

function GetItem(Index: Integer): TElement;
begin
 CheckIndex(Index);
 Result := FItems[Index]
end;

procedure SetItem(Index: Integer; const Value: TElement);
begin
 CheckIndex(Index);
 FItems[Index] := Value
end;

procedure Add(const Element: TElement);
begin
 SetLength(FItems, Length(FItems) + 1);
 FItems[High(FItems)] := Element
end;

procedure Delete(Index: Integer);
begin
 CheckIndex(Index);
 if Index < Count - 1 then
   Move(FItems[Index + 1], FItems[Index],
     (Length(FItems) - Index - 1) * SizeOf(TElement));
 SetLength(FItems, Length(FItems) - 1)
end;

Вот в таком ключе и действуйте. Удачи!


 
Тимохов ©   (2004-04-27 18:21) [9]


> Юрий Зотов ©   (27.04.04 18:13) [8]

Вот для меня всегда был темным следующий вопрос - бывают ли динамические массивы не packed? Я неоднократно встречал, что люди пишут packed даже для динамических массивов, но я не встречал в своей практике динамический массивы, которые были бы неупакованными даже без packed...


 
WebErr ©   (2004-04-27 18:22) [10]


> Юрий Зотов ©   (27.04.04 18:13) [8]

кстати, давно хотел спросить, для чего нужны packed?


 
Jack128 ©   (2004-04-27 18:31) [11]

packed + f1:
Instances of a structured type hold more than one value. Structured types include sets, arrays, records, and files as well as class, class-reference, and interface types. Except for sets, which hold ordinal values only, structured types can contain other structured types; a type can have unlimited levels of structuring.
By default, the values in a structured type are aligned on word or double-word boundaries for faster access. When you declare a structured type, you can include the reserved word packed to implement compressed data storage. For example,

type TNumbers = packed array[1..100] of Real;

Using packed slows data access and, in the case of a character array, affects type compatibility. For more information, see Memory management.


 
Гаврила ©   (2004-04-27 18:36) [12]

>>WebErr ©   (27.04.04 18:22) [10]

Для отключения выравнивания при хранении в памяти.
Выравнивание включается для ускорения доступа. Например выравнивание по 8 бат. То есть следующий элемент массива начинается не с момента окончания предыдущего, а с ближайшего адреса кратного 8


 
Тимохов ©   (2004-04-27 18:42) [13]

Юрию Зотову.
Поясню, почему задал о том играет ли какую нибудь роль packed около динамических массивов.
Я недавно разбирался с внутренним устройством динамических массивов, в частности с методом DynArraySetLength. Я не заметил там норвый размер массива расчитывается как neededSize := newLength*elSize; Т.е. просто умножением. Вот меня и заинтересовало зачем писать packed около array of?


 
WebErr ©   (2004-04-27 18:42) [14]


> Jack128 ©   (27.04.04 18:31) [11]

Спасибо.
В смысле данные выравниваются по слову/двойному слову?
Это единственное, что их выгодно отличает от unpacked?
Впрочем, ускорение доступа уже - солидное преимущество! 8)


 
WebErr ©   (2004-04-27 18:43) [15]


> Гаврила ©   (27.04.04 18:36) [12]

Спасибо.
С русского переводить привычнее! :))))


 
Юрий Зотов ©   (2004-04-27 19:00) [16]

> Тимохов ©   (27.04.04 18:21) [9]

> бывают ли динамические массивы не packed?

Формально - бывают, неформально - до сих пор я не проверял, но полагал, что тоже бывают. Однако же, вот только что проверил, и получил, что, похоже, компилятор сам делает их packed. Возможно, потому, что так проще рассчитывать сдвиг при адресации элементов.

var
 A: array of byte;

procedure TForm1.FormCreate(Sender: TObject);
var
 P: PByte;
begin
 SetLength(A, 2);
 P := @A[0];
 Inc(P, 1);
 P^ := 255;
 A[0] := 1;
 A[1] := 2;
 Caption := Format("%d %d %d", [A[0], P^, A[1]])
end;

Однако же, эта фича относится к реализации, и завтра может измениться, поэтому, когда требуется атрибут packed, то лучше все же писать его в явном виде. В данном случае я написал packed из-за Move.


 
Тимохов ©   (2004-04-27 19:07) [17]


>  похоже, компилятор сам делает их packed

вот я тоже так думаю.

Самое инетресное, что у меня сейчас в течении 20 минут не получилось сделать массива (НЕ динамического) упакованных записей, чтобы sizeof этого массива НЕ равнялся count*sizeof(element). Насколько я понимаю, такое не равенство должно быть, когда компилятор в угоду оптимальности располагает элементы массива не подряд.

Вы можете привести пример не упакосанного массива.


 
Тимохов ©   (2004-04-27 19:09) [18]


> Однако же, эта фича относится к реализации, и завтра может
> измениться, поэтому, когда требуется атрибут packed, то
> лучше все же писать его в явном виде. В данном случае я
> написал packed из-за Move.

В этом я с вами полностью согласен.
Сам так всегда делаю - если move, то packed все что можно.
Но все же - хотелось бы лучше понимать устройство?

Вдруг кто-нибудь на собеседовании задаст такой вопрос? :)))


 
Alexus12   (2004-04-27 20:40) [19]

Тимохов и Юрий Зотов !!!
Огромнейшее спасибо за код!!!
Буду пробовать!

Еще маленький вопрос:
немножко не понимаю, где ниже объявляется
массив RESULT типа TMas
(это вроде procedure, а result - атрибут function???)
да и массивы должны быть одинаковых типов
для присваивания элементов, или чего не понимаю?....

Итак, открытый вопрос:
Как вернуть результирующий массив - подмножество основного массива - в вызывающую метод Find процедуру?

procedure TCl.Find(const ...): TMas;
var
 I: Integer;
begin
 Result := nil;
 for I := 0 to High(fMas) do
 begin
    if fMas[I] удовлетворил условию, тогда добавим его в Result:
    Setlength(Result, Length(REsult)+1);
    Result[High(Result)] := fMas[I];
 end;
end;

Еще раз всем спасибо!


 
Jack128 ©   (2004-04-27 21:00) [20]


> если move, то packed все что можно

А можно вопрос, зачем?
var
rec1, rec2: record
 b1, b2, b3: byte
end;
begin
 with r1 do
 begin
   b1 := 12;
   b2 := 74;
   b3 := 52;
 end;
 Move(r1, r2, SizeOf(r1)); // разве это не корректно?
end;


 
Юрий Зотов ©   (2004-04-27 22:10) [21]

> Jack128 ©   (27.04.04 21:00) [20]

Это корректно. Но если нужно разом переместить несколько смежных элементов массива, а этот массив все же не будет packed - как вычислить количество перемещаемых байт?


 
Alexus12   (2004-04-27 22:18) [22]

Ну как же с поиском-то быть, родные (метод FIND)?..
Как - получив строку для поиска - вернуть маленький массив
отобранных из большого массива элементов ???


 
Jack128 ©   (2004-04-27 22:41) [23]


> как вычислить количество перемещаемых байт

Можно предположить, что размер массива arr: array of TRec равен
case Length(arr) of
0: Result := 0;
1: Result := SizeOf(TRec) ; // неучитываем выравнивание, но в данном случае это не важно
else
 Result := (Integer(@arr[1]) - Integer(@arr[0])) * Length(arr);


 
Юрий Зотов ©   (2004-04-28 00:20) [24]

> Jack128 ©   (27.04.04 22:41) [23]

НЕСКОЛЬКО СМЕЖНЫХ. С одним проблем нет.

> Alexus12 (27.04.04 22:18) [22]

Можно ввести событие. Когда метод Find находит строку, он возбуждает это событие и вызывается его обработчик. В нем можно делать что угодно - хоть массив формировать, хоть еще что.

type
 TElements = class;
 TFindElement = procedure(Sender: TElements; Index: Integer) of object;
 TElements = class
 private
   ...
   FOnFindElement: TFindElement;
   ...
 protected
   procedure DoFindElement(Index: Integer); dynamic;
   ...
 public
   ...
   procedure Find(Source: string);
   ...
   property OnFindElement: TFindElement
     read FOnFindElement write FOnFindElement;
 end;  

procedure Find(Source: string);
var
 i: integer;
begin
 for i := 0 to Count - 1 do
   if FItems[i].F1 = Source then DoElement(i)
end;

procedure DoFindElement(Index: Integer);
begin
 if Assigned(FOnFindElement) then
   FOnFindElement(Self, Index)
end;


 
evvcom ©   (2004-04-28 00:31) [25]


> (это вроде procedure, а result - атрибут function???)

Result не атрибут, а результат функции. Явно в функции это не прописывается, так же как не прописывается и Self в классах - указатель на существующий объект (элемент) класса.
Например, в

function One: Integer;
begin
// можно так, как в древнем (базовом) паскале
One := 1;
// а можно так, это равнозначно
Result := 1;
end;

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


 
Jack128 ©   (2004-04-28 00:36) [26]


> Юрий Зотов ©   (28.04.04 00:20)
> > Jack128 ©   (27.04.04 22:41) [23]
>
> НЕСКОЛЬКО СМЕЖНЫХ. С одним проблем нет.
ну?

чтобы переместить Count СМЕЖНЫХ элементов массива начиная с Index на участок памяти p(считаем, что Count > 0)

var
 p: Pointer;
 Size: Integer;
begin

 Size := (Integer(@arr[Index + 1]) - Integer(@arr[Index])) * Count;
 GetMem(P, Size);
 try
   Move(arr[Index], P^, Size);
  ...
 finally
   FreeMem(p);
 end;

end;


 
evvcom ©   (2004-04-28 01:03) [27]

Что-то вы заинтриговали меня. Проверил

type
 TRec = record
   i: Integer;
   b: Byte;
 end;

var
 l_iSize: Integer;
begin
 l_iSize := SizeOf(TRec); // как и положено с выравниванием = 8
end;


также создал array of TRec; все четко каждая запись по 8 байт.


 
evvcom ©   (2004-04-28 01:20) [28]

Поэтому Jack128 ©   (27.04.04 22:41) [23]
равносильно: SizeOf(arr) = Length(arr) * SizeOf(TRec)


 
Alexus12   (2004-04-28 09:53) [29]

>evvcom 28.04.04 00:31) [25]
>Result не атрибут, а результат функции

Понимаю про существование этой переменной у _function_
В примере же, про который этот вопрос задан, result использовалась без объявления в _procedure_
Она в ней тоже существует?????

[Пост 7]
procedure TCl.Find(const ...): TMas;
var
I: Integer;
begin
Result := nil;


 
Alexus12   (2004-04-28 09:55) [30]

Еще раз огромное спасибо всем откликнувшимся, особенно авторам кода - все получилось, даже запись в файл методом класса!

Еще маленький вопрос по передаче массива значений из процедуры
Делаю так:

В вызывающей процедуре объявляю динамический массив (элемент массива = запись):
var
Temp: MAS;
ReturnCount:integer;

делаю размер Temp равным размеру массива, в котором будет производиться поиск
seltength(Temp,Lengh(Осн_Массив))

и вызываю функцию поиска:

shablon:="чтоищу";
ReturnCount=Find(shablon, Temp);

Эта функция
пробегает по своим данным (Осн_Массив того же типа MAS)
и если считает очередной элемент достойным внимания (сложный алгоритм)
добавляет его к выходному (объявленному в вызывающей процедуре как Temp)
и одновременно увеличивает свой Result на 1

Таким образом
по завершении сканирования Осн_Массива
имеем в вызывающей процедуре:
в массиве Temp = отобранные записи из Осн_Массива плюс кучу неиспользованных элементов
в ReturnCount - кол-во найденных записей

Вопрос:
есть ли более совершенные приемы работы по возврату массива из процедуры?
Понимаю, что можно вернуть вместо самих записей только их индексы
- что сильно сократит использовании памяти
(сейчас если поиск вернет все записи, Temp будет занимать столько же, сколько Осн_Массив),
а какие еще пути?

Вижу вариант с событием,
от Юрий Зотов ©   (28.04.04 00:20) [24]
но уж больно круто это для меня 8-(

Как можно не определять размер Temp перед вызовом
= выбросить seltength(Temp,Lengh(Осн_Массив))
и заставить саму Find приращивать размер выходного массива по необходимости?
Насколько понимаю из справки, процедура не может изменить размерность переданного ей как параметра массива?


 
Тимохов ©   (2004-04-28 10:03) [31]


> Alexus12   (27.04.04 20:40) [19]
> Итак, открытый вопрос:
> Как вернуть результирующий массив - подмножество основного
> массива - в вызывающую метод Find процедуру?

Вы издеваетесь, я же вам написал find...

Всем исследователям packed.

Вчера вечером дома бился, чтобы добится того, чтобы массив был НЕ packed. При это данное утвержение кассается также и НЕ динамических массивов. Не вышло! Вот элементы массива (записи) НЕ packed - пожалуйства, а сами элементы - фиг.

Но. Главное что я для себя вывел, что явно в документации не сказано (я не нашел), что динамические массивы всегда packed. Поэтому я все же буду продолжать (как и советовал Юрий Зотов) всегда писать packed, если мне нужно делать move.

Если кто-то все же найдет кусок доки, где сказано, что дин. массивы могут быть не packed, скажите пожалуйста.

Еще одна просьба - если у кого-то получится сделать НЕ упакованный НЕ динамический массив, также скажите пожалуйста.


 
Alexus12 ©   (2004-04-28 10:09) [32]

!


 
Тимохов ©   (2004-04-28 10:16) [33]


> Насколько понимаю из справки, процедура не может изменить
> размерность переданного ей как параметра массива?

зависит от того, как передать.


> - что сильно сократит использовании памяти


В вашей задаче это важно.

Можете индексы передавать...


 
Alexus12 ©   (2004-04-28 10:17) [34]

>Вы издеваетесь, я же вам написал find...
Уважаемый Тимохов!
Прощу прощения, но я правда не понимаю 8(((
Вот что значит переходить с языка на язык 8((
например в VB невозможно вернуть результат ПРОЦЕДУРЫ - он существует только у функции,
чем они друг от друга и отличаются

Я правильно понимаю, что procedure в дельфи тоже не может иметь результата?
Тогда что такое Result ниже и где его нужно объявить?...
или просто заменить procedure TCl.Find(const ...): TMas;
на FUNCtion  TCl.Find(const ...): TMas;
и пользоваться?

Ваш код:
procedure TCl.Find(const ...): TMas;
var
I: Integer;
begin
Result := nil;
for I := 0 to High(fMas) do
begin
if fMas[I] удовлетворил условию, тогда добавим его в Result:
Setlength(Result, Length(REsult)+1);
Result[High(Result)] := fMas[I];
end;
end;


 
Тимохов ©   (2004-04-28 10:20) [35]


> Alexus12 ©   (28.04.04 10:17) [34]

виноват - я find назвал процедурой, назовите ее функцией.
т.е. function find(.....): TMas;

могли бы догадаться - это все основы языка...


 
Тимохов ©   (2004-04-28 10:21) [36]


> Тимохов ©   (28.04.04 10:20) [35]

собственно вы и догадались...
значит не все потеряно... :)


 
evvcom ©   (2004-04-28 10:31) [37]


> Как можно не определять размер Temp перед вызовом
> = выбросить seltength(Temp,Lengh(Осн_Массив))
> и заставить саму Find приращивать размер выходного массива
> по необходимости?
> Насколько понимаю из справки, процедура не может изменить
> размерность переданного ей как параметра массива?

А что сложного?

function Find(..., var Arr: TMas): Integer;
var
 l_iIndex: Integer;
begin
 l_iIndex := Length(Arr);
 SetLength(Arr, l_iIndex + 1);
 Arr[l_iIndex] := ...;
 ...
end;


 
Alexus12 ©   (2004-04-28 10:33) [38]

было бы слегка удивительно с дипломом по VB жить как будто все потеряно ;)
но в дельфях я еще чайник, что често признаю 8(
вот и пытаюсь научиться, спасибо за помощь огромное!

>> Насколько понимаю из справки, процедура не может изменить
>> размерность переданного ей как параметра массива?
>зависит от того, как передать.

Подскажите, пожалуйста, как передать, чтобы могла?..


 
Тимохов ©   (2004-04-28 10:43) [39]


> Alexus12 ©   (28.04.04 10:33) [38]


> Подскажите, пожалуйста, как передать, чтобы могла?..

procedure add(var m: tmas);
begin
  setlength(m, length(m)+1))
  m[high(m)] := ...;
end;


 
evvcom ©   (2004-04-28 10:43) [40]


> Подскажите, пожалуйста, как передать, чтобы могла?..

см. [37]



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

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

Наверх




Память: 0.6 MB
Время: 0.026 c
11-1068754184
puky
2003-11-13 23:09
2004.05.16
KOLCDWriter ? где он?


1-1083225929
Игорь
2004-04-29 12:05
2004.05.16
Когда я пишу в RichEdit текст вот такой


11-1069519122
BelchonokH
2003-11-22 19:38
2004.05.16
Максимизация формы


1-1082973772
=DEV=
2004-04-26 14:02
2004.05.16
И опять StringGrid ...


1-1083649698
konstantinov
2004-05-04 09:48
2004.05.16
Как вывести сообщение поверх всех окон