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

Вниз

Динамические массивы - правильно ли я понял help?   Найти похожие ветки 

 
Ega23 ©   (2005-06-01 14:41) [0]

Никогда не работал с дин.массивами. Хочется узнать - правильно ли я понял, как с ними работать?

Допустим:
var
a:array of Integer;

begin
SetLength(a, 5); // в массиве 5 элементов.
a[0]:=1; a[4]:5; // Индексация в массиве - с 0 до Length(a)-1
SetLength(a, 6); // Сохранились ли предыдущие значения a[0] и a[4]?
SetLength(a, 0) // Опреация по освобождению массива
end;

Так ли это?


 
begin...end ©   (2005-06-01 14:43) [1]

> Ega23 ©   (01.06.05 14:41)

> Сохранились ли предыдущие значения a[0] и a[4]?

Да.

> Опреация по освобождению массива

Если это уже конец подпрограммы, то это делать необязательно. Дин. массив освободится автоматически пр выходе из области видимости.


 
TUser ©   (2005-06-01 14:43) [2]

Все правильно. Элементы 0-4 сохранятся. + хорохо бы еще finally поставить.

Hint: Если массив объявлен как локальная переменная, то Delphi гарантирует освобождение памяти по завершении работы процедуры.


 
Юрий Зотов ©   (2005-06-01 14:45) [3]

> в массиве 5 элементов.
Да.

> Индексация в массиве - с 0 до Length(a)-1
Да. Еще можно использовать Low(a) и High(a).

> Сохранились ли предыдущие значения a[0] и a[4]?
Да. Сохранились вообще все элементы, включая и мусорные.

> Опреация по освобождению массива
Либо так, либо a := nil.


 
Ega23 ©   (2005-06-01 14:46) [4]

Спасибо всем.


 
Ega23 ©   (2005-06-01 14:52) [5]

Вдогонку ещё один вопрос:
Могу ли я после задания длины массиву (SetLength(a, Count)) использовать переменную a в виде буфера при чтении из Stream?

var
a:array of integer;
Count:Integer;
ms:TMemoryStream;
begin

ms:=TMemoryStream.Create;
try
 TBLOBField(Query1.FieldByName("Data")).SaveToStream(ms);
 Count:=Query1.FieldByName("DataLength").AsInteger;
 ms.Position:=0;
 SetLength(a, Count);
 ms.ReadBuffer(a, Count*SizeOf(Integer));
 
  ......

finally
 ms.Free;
 a:=nil;
end;

end;


 
Amoeba ©   (2005-06-01 14:54) [6]

ms.ReadBuffer(a[0], Count*SizeOf(Integer));


 
Ega23 ©   (2005-06-01 14:57) [7]

А почему a[0]?


 
begin...end ©   (2005-06-01 14:59) [8]

> Ega23 ©   (01.06.05 14:57) [7]

Потому что иначе (как в коде [5]) ты будешь читать не в область, в которой расположены элементы массива, а в указатель на эту область.


 
КаПиБаРа ©   (2005-06-01 14:59) [9]

Ega23 ©   (01.06.05 14:57) [7]
Так нада.
a[0] - адрес первого элемента массмива
a - адрес где храится сцылка на a[0]


 
begin...end ©   (2005-06-01 15:01) [10]

> КаПиБаРа ©   (01.06.05 14:59) [9]

> a[0] - адрес первого элемента массмива

a[0] -- это не адрес. Это сам элемент.


 
Ega23 ©   (2005-06-01 15:02) [11]

Ага, спасибо. В общем, всё также, как и в "ручном" формировании динамического массива, только без GetMem - FreeMem


 
evvcom ©   (2005-06-01 15:02) [12]


> А почему a[0]?

Потому что procedure ReadBuffer(var Buffer; Count: Longint);
Передаешь a[0] по ссылке, компилятор подставляет адрес 0-го элемента, если передавать a, то передашь адрес переменной a-указателя на динамический массив.


 
evvcom ©   (2005-06-01 15:05) [13]


> только без GetMem - FreeMem

зато с (+) Length, Low и High, хотя для дин.массивов Low всегда = 0


 
Ega23 ©   (2005-06-01 15:36) [14]

Откровенно говоря, когда в университете проходили списки и способы их построения, всяческими array of и TList при написании заданий пользоваться было категорически запрещено.
Ну, TList я с тех пор худо-бедно освоил :)
А вот с массивами как-то не срослось. Да и надобности не было...


 
Юрий Зотов ©   (2005-06-01 16:54) [15]

> Ega23 ©   (01.06.05 14:52) [5]

Чтобы использовать что-то типа
ReadBuffer(a[0], Length(a) * SizeOf(тип_элемента))
массив, строго говоря, должен быть объявлен так:
a: packed array of тип_элемента

Тут этот вопрос когда-то обсуждался и выяснилось, что компилятор пакует массивы даже и при отсутствии packed, но я бы все же рекомендовал указывать packed явно. Как минимум, по трем причинам:
- гарантирует от возможных коллизий в будущих версиях;
- дисциплинирует мозги;
- код становится прозрачнее.


 
Ega23 ©   (2005-06-01 17:21) [16]


> a: packed array of тип_элемента

Спасибо. Это ценная информация.
Для статических массивов при описании структуры я packed использую, но про динамические - не знал.


 
Суслик ©   (2005-06-01 17:25) [17]


>  [15] Юрий Зотов ©   (01.06.05 16:54)

Знаешь, Юрий, на слово packed кладут, как мне показалось все, в том числе и сами разработчики borland. Такое ощущение, что они не собираются реализовывать соответствующую семантику вообще.

Я, кстати, всегда пишу, когда это нужно. Но есть ощущение, что это лишнее.


 
Defunct ©   (2005-06-02 03:18) [18]

Юрий Зотов ©   (01.06.05 16:54) [15]
> строго говоря, должен быть объявлен так:
> a: packed array of тип_элемента

скорее, не строго говоря, а в тех случаях когда тип_элемента - record и не объявлен с ключевым словом packed либо не кратен 4.

a: packed array of integer  
не красиво ;>
А вдруг (что маловероятно) первый элемент при этом окажется невыровняным на границу Dword? тогда работа с таким массивом на некоторых процессорах будет неоправдано медленной.


 
begin...end ©   (2005-06-02 09:12) [19]

> Defunct ©   (02.06.05 03:18) [18]

> скорее, не строго говоря, а в тех случаях когда тип_элемента
> - record и не объявлен с ключевым словом packed либо не
> кратен 4.

И на что в этом случае повлияет слово packed перед array?


 
evvcom ©   (2005-06-02 09:27) [20]


> А вдруг (что маловероятно) первый элемент при этом окажется
> невыровняным на границу Dword

Первый уж точно будет выровнен, вот остальные ...


 
Defunct ©   (2005-06-02 09:44) [21]

> begin...end

не знаю. А что вы об это думаете?


> evvcom
там же ж слово packed, остальные будут будут "притиснуты" друг к другу.


 
begin...end ©   (2005-06-02 09:45) [22]

> Defunct ©   (02.06.05 09:44) [21]

> А что вы об это думаете?

Я думаю, что никак.


 
begin...end ©   (2005-06-02 09:46) [23]

В смысле, ни на что не повлияет.


 
Defunct ©   (2005-06-02 09:54) [24]

мне все-таки кажется, что хотя бы record к record"у прижмет вплотную.


 
begin...end ©   (2005-06-02 09:55) [25]

> Defunct ©   (02.06.05 09:54) [24]

А разве без packed перед array записи не будут прижаты друг к другу?


 
evvcom ©   (2005-06-02 09:56) [26]


> там же ж слово packed, остальные будут будут "притиснуты"
> друг к другу

Я это знаю. Я говорил о варианте без packed.


 
jack128 ©   (2005-06-02 09:57) [27]

Defunct ©   (02.06.05 9:44) [21]
там же ж слово packed, остальные будут будут "притиснуты" друг к другу

не на всех платформах SizeOf(Integer) = Size(DWord). Хотя на это можно забить.

Defunct ©   (02.06.05 3:18) [18]
скорее, не строго говоря, а в тех случаях когда тип_элемента - record и не объявлен с ключевым словом packed либо не кратен 4

На самом деле если еще более абстрагироваться от конкретных платформ, то неупаковонный массив должен обеспечивать наиболее быстрый доступ к массиву. То что сейчас фактический это означает выравнивание на Dword не означает, что так будет в будущем...
Хотя разговор довольно бессмысленный так как

Суслик ©   (01.06.05 17:25) [17]
на слово packed кладут, как мне показалось все, в том числе и сами разработчики borland. Такое ощущение, что они не собираются реализовывать соответствующую семантику вообще.


 
Defunct ©   (2005-06-02 10:01) [28]

begin...end ©   (02.06.05 09:55) [25]

Возможены случаи когда не будут.
SizeOf(<Record>) = 31, будут или не будут?


 
Defunct ©   (2005-06-02 10:03) [29]

> jack128
> Хотя разговор довольно бессмысленный так как

ну для чего-то же все-таки есть ключевое слово packed. не может быть чтобы оно было просто бессмысленным.


 
Игорь Шевченко ©   (2005-06-02 10:10) [30]

jack128 ©   (02.06.05 09:57) [27]


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


Безусловно.

Defunct ©   (02.06.05 10:03) [29]


> ну для чего-то же все-таки есть ключевое слово packed. не
> может быть чтобы оно было просто бессмысленным


Совершенно не бессмысленное. Во-первых, оно обеспечивает совместимость на уровне двоичного кода функций, написанных на разных языках, во-вторых, не все данные в жизни являются неупакованными, пример - заголовок исполняемого файла


 
Defunct ©   (2005-06-02 10:29) [31]

> Игорь Шевченко
> Во-первых, оно обеспечивает совместимость на уровне двоичного кода функций, написанных на разных языках

Напрашивается вопрос.

TRecord = record
F1..FN : Sometype
...
End;


TArray = packed array of TRecord

Будет ли TArray соответствовать вышесказанному?


 
Ega23 ©   (2005-06-02 10:34) [32]

2 Defunct ©   (02.06.05 10:29) [31]

Насколько я понял, имеется ввиду совместимость структуры на C и рекорда в Delphi. Ну, грубо говоря, как соглашение о вызове у функции.
Я packed использовал только для чтения хитрых бинарников и формировании данных для передачи по сети.


 
Юрий Зотов ©   (2005-06-02 10:39) [33]

> Defunct ©   (02.06.05 03:18) [18]

> скорее, не строго говоря, а в тех случаях когда
> тип_элемента - record и не объявлен с ключевым
> с ключевым словом packed либо не кратен 4.

Имеем динамический массив A с типом элемента byte. Есть поток MS класса TMemoryStream размером 12 байт, которые содержат:
$01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C

Программа содержит операторы:

SetLength(A, MS.Size);
MS.Position := 0;
MS.ReadBuffer(A[0], Length(A) * SizeOf(byte));

Теперь вопрос (напоминаю, что директива packed имеет значение, если говорить именно строго - то есть, когда отсутствие этой директивы компилятором НЕ игнорируется, как оно и должно быть). Итак:

Как будет заполнен массив A в каждом из двух случаев:
- когда он упакован;
- когда он НЕ упакован.

Ответы:

- упакованный массив будет содержать в себе точную копию тела потока (поэлементно - см. выше).

- говоря строго, неупакованный массив будет содержать в себе следующее (буква M означает элемент массива, содержащий "мусор"):
$01 $05 $09 М M M M M M M M M
(предполагается умалчиваемое выравнивание для 32-битных платформ - на границу двойного слова).

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

Что же мы видим уже на этом элементарном примере?
1. Заполнение массива зависит от его упакованности именно говоря строго.
2. Никакие record"ы тут ни при чем - различие наблюдается даже на скалярных типах.


 
Defunct ©   (2005-06-02 10:41) [34]

packed = упакованый.
не обращаясь к справке, только по смыслу этого слова можно допустить, что независимо от компилятора каждое поле упакованой структуры будет размещено байт к байту с другими полями.
Вот собсно в этом вопрос, так ли это.

Достатоточно ли объявить packed array of TRecord, чтобы неупакованые записи стали упаковаными в массиве?


 
Defunct ©   (2005-06-02 10:44) [35]

> Юрий Зотов
запостил [34] до того как появился Ваш ответ [33]. Но тем не менее если не трудно, можете ответить на [34]?


 
evvcom ©   (2005-06-02 10:49) [36]


> Достатоточно ли объявить packed array of TRecord, чтобы
> неупакованые записи стали упаковаными в массиве?

Допустим SizeOf(TRecord)=6. Принимая во внимание сказанное (написанное) Юрием, packed array[0..1] будет состоять из 12 байт, а не упакованный из 16. Сами же TRecord как были не упакованными, так и останутся.


 
Юрий Зотов ©   (2005-06-02 10:52) [37]

> Defunct ©   (02.06.05 10:44) [35]

Точно не знаю, не проверял. Но можно проверить указанным в [33] способом.


 
evvcom ©   (2005-06-02 10:54) [38]

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


 
Defunct ©   (2005-06-02 10:56) [39]

evvcom ©   (02.06.05 10:49) [36]

Вполне логично, вечером проверю. Сейчас под рукой нет ни Delphi ни даже справки от него.


 
evvcom ©   (2005-06-02 11:09) [40]

Я уже проверил.

type
 TRecord = record
   c: Char;
   w: WORD;
   w1: WORD;
 end;
const
 ac1: TRecord = (c: "A"; w: $10; w1: $55);
 ac2: TRecord = (c: "B"; w: $20; w1: $AA);

var
 a1: array[0..1] of TRecord;
 a2: packed array[0..1] of TRecord;
begin
 a1[0] := ac1;
 a1[1] := ac2;
 a2[0] := ac1;
 a2[1] := ac2;
end;
компилятор не делает разницы между packed array и не packed. Оба массива занимают по 12 байт:
41 00 10 00 55 00 42 00 20 00 AA 00
все hex


 
evvcom ©   (2005-06-02 11:10) [41]

+ А вот элементы массива по 6 байт, т.е. SizeOf(TRecord)


 
Defunct ©   (2005-06-02 11:15) [42]

> evvcom

ок, теперь все понятно. Вы были правы в [36].

> компилятор не делает разницы между packed array и не packed

А как же заставить компилятор чтобы массив был НЕ упакованым?
т.е. то про что говорил ЮЗ:
когда отсутствие этой директивы компилятором НЕ игнорируется


 
Суслик ©   (2005-06-02 11:17) [43]


> А как же заставить компилятор чтобы массив был НЕ упакованым?
>

А оно вам надо?


 
Суслик ©   (2005-06-02 11:20) [44]


> [42] Defunct ©   (02.06.05 11:15)

С трудом могу представить, когда это нужно. Как я говорил на это кладут сами разработчики borland. Не скажу где (т.к. не помню), но я вдиел в глубинах vcl игнорирование packed, хотя по месту это было необходимо.

Я сейчас постю и читаю группы на borland.com. Будет время спрошу про это.


 
Anatoly Podgoretsky ©   (2005-06-02 11:24) [45]

Defunct ©   (02.06.05 10:41) [34]
Достатоточно ли объявить packed array of TRecord, чтобы неупакованые записи стали упаковаными в массиве?

В данном контексте packed относится к самому массиву, а не элементам записи.


 
Defunct ©   (2005-06-02 11:30) [46]

> Суслик

Честно говоря - надо. Иначе бы и не спрашивал. Некоторые SSE команды работают только с данными, выровненными на границу QWORD иначе exception.


 
evvcom ©   (2005-06-02 11:32) [47]


> А как же заставить компилятор чтобы массив был НЕ упакованым?
...
> Честно говоря - надо.

type
TRecord = record
  c: Char;
  w: WORD;
  w1: WORD;
  reserved: WORD;
end;


 
Alx2 ©   (2005-06-02 11:33) [48]

Defunct ©   (02.06.05 11:30) [46]

Кажется, есть аналоги для невыровненных данных.


 
Defunct ©   (2005-06-02 11:39) [49]

evvcom ©   (02.06.05 11:32) [47]
На данный момент именно так и поступаю.

Alx2 ©   (02.06.05 11:33) [48]

Но они работают медленнее почти в 2 раза
речь о
movdqa
и
movdqu


 
Alx2 ©   (2005-06-02 12:03) [50]

Defunct ©   (02.06.05 11:39) [49]
Увы. Компилятор Delphi (по крайней мере D6) не умеет делать требуемое выравнивание.

Чтобы это обойти, в критичных по скорости участках, я использую DLL, скомпилированные Intel C++ compiler. У него, кстати, кроме уже стандартных MMX, SSE, SSE2, SSE3 (в частности, для них он автоматом производит векторизацию и распараллеливание) есть оптимизация и под 64-битную архитектуру Itanium - пока еще большая редкость.


 
begin...end ©   (2005-06-02 12:08) [51]

> Defunct ©   (02.06.05 10:01) [28]

> Возможены случаи когда не будут.

Если утверждаете, то, вероятно, можете привести пример. Хотелось бы увидеть.

> SizeOf(<Record>) = 31, будут или не будут?

Будут.

> Defunct ©   (02.06.05 10:29) [31]

> TArray = packed array of TRecord
> Будет ли TArray соответствовать вышесказанному?

TArray будет упакованным, а его элементы будут неупакованными.

> Defunct ©   (02.06.05 10:41) [34]

> packed = упакованый.
> не обращаясь к справке, только по смыслу этого слова можно
> допустить, что независимо от компилятора каждое поле упакованой
> структуры будет размещено байт к байту с другими полями.
> Вот собсно в этом вопрос, так ли это.

Если запись объявлена с packed, то поля записи будут прижаты.
Если массив объявлен с packed, то элементы массива будут прижаты.
Если массив объявлен без packed, то элементы всё равно будут прижаты.

> Достатоточно ли объявить packed array of TRecord, чтобы
> неупакованые записи стали упаковаными в массиве?

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

По-моему, всё логично и понятно. Кроме того, что массивы всегда (независимо от наличия packed) упаковываются.


 
TUser ©   (2005-06-02 12:08) [52]

> > А как же заставить компилятор чтобы массив был НЕ упакованым?  

Можно обявить array of TCoolRecord, где в TCoolRecord забить нужное кол-во бополнительных полей соотвествующего размера, например
TCoolRecord =
record
  B1, B2: boolean; // 2 байта
  C1, С2, С3: shortint; // 3 байта
  Zero: array [0..2] of byte; // not used
end;

Интересно, не с этим ли связано появление reserved агрументов в некоторых API функциях?)


 
Defunct ©   (2005-06-02 12:18) [53]

> begin...end

Все было просто отлично, доходчиво и логично, до вот этого:

По-Вашему, компилятор будет брать каждое поле из присваиваемой записи и помещать его в соответствующее поле упакованного элемента массива, вместо того чтобы скопировать целиком неупакованную запись?

Обязательно надо было ложку дёгтя в бочку мёда засунуть?
Было бы "по-моему" еще неизвестно как сделал бы.

> не с этим ли связано появление reserved агрументов в некоторых API функциях

Вполне возможно.


 
begin...end ©   (2005-06-02 12:23) [54]

> Defunct ©   (02.06.05 12:18) [53]

> Обязательно надо было ложку дёгтя в бочку мёда засунуть?
> Было бы "по-моему" еще неизвестно как сделал бы.

Я просто не понял, как Вы себе представляете действия компилятора в данном случае. Потому и спросил.


 
evvcom ©   (2005-06-02 12:39) [55]

Кстати, переделал код:

type
TRecord = record
  dw: DWORD;
  c: Char;
end;
const
ac1: TRecord = (dw: $11111111; c: "A");
ac2: TRecord = (dw: $22222222; c: "B");

var
a1: array[0..1] of TRecord;
a2: packed array[0..1] of TRecord;
begin
a1[0] := ac1;
a1[1] := ac2;
a2[0] := ac1;
a2[1] := ac2;
end;

Компилятор между этими массивами опять не видит никакой разницы, но результат теперь такой:
11 11 11 11 41 00 00 00
22 22 22 22 42 00 00 00

Проверил SizeOf(TRecord), теперь он =8, хотя в предыдущем был =6. Вот этим 8 и 6 я что-то объяснения найти не могу пока.


 
Sapersky   (2005-06-02 15:15) [56]

Логика выравнивания полей неупакованных записей довольно хитрая, это не просто "расставить поля по адресам кратным 4".
См. хелп: Object Pascal Reference \ Memory management \ Record types
Массивы, видимо, выравниваются по такому же принципу.



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

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

Наверх




Память: 0.63 MB
Время: 0.03 c
3-1116321269
_Max
2005-05-17 13:14
2005.06.29
DBGrid - строки разной высоты


1-1118126471
Леонид
2005-06-07 10:41
2005.06.29
Как запретить ввод значений в combobox


1-1117781895
qyu
2005-06-03 10:58
2005.06.29
Как в Grid


6-1112326674
atruhin
2005-04-01 07:37
2005.06.29
Влияние Content-Length на Keep-Alive в HTTP протоколе


1-1118060894
Mr.F
2005-06-06 16:28
2005.06.29
Оптимальная сортировка