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

Вниз

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

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

Наверх




Память: 0.58 MB
Время: 0.038 c
6-1080036190
alexprozorov
2004-03-23 13:03
2004.05.16
Проблема нотификационных сообщений


14-1083156610
Vvv
2004-04-28 16:50
2004.05.16
Приколы по сети


3-1082221283
CyBeR
2004-04-17 21:01
2004.05.16
Как создать список просмотра DbGrid????


14-1082953057
AGAMEMNUM
2004-04-26 08:17
2004.05.16
photoshop


1-1083223110
BALU1111
2004-04-29 11:18
2004.05.16
EConvertError ...





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский