Форум: "Основная";
Текущий архив: 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