Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Открытый массив


Автор: Scrip 24.5.2004, 14:38
Можно ли считать открытый массив динамическим массивом предствляющим собой параметр подпрограммы?
__________________________________________________________
Что такое конструктор массива и для чего он нужен?

Автор: Kesh 24.5.2004, 17:29
Мне вопрос непонятен, поясни, что такое открытый массив?..
Добавлено @ 17:35
Что ты имеешь в виду под конструктором массива? SetLength?

Автор: Jey_k 24.5.2004, 22:14
Scrip
массивы можно, конечно, передавать как параметры подпрограммы, а что такое открытый массив?
Уж не объявленный ли глобально?
А динамический массив, насколько мне известно, тот у которого размерность может менятся в нужных случаях.

Если все так, то связи в первом предложении не вижу(не обижайся, может не так понял)
А конструктор-процедура создания.

qwe:array[1..10] of integer; например

Автор: p0s0l 25.5.2004, 01:23
Открытый массив - массив неизвестного размера. Пример:
Код
procedure Proc1(var m : array of integer);
var i : integer;
begin
 for i := Low(m) to High(m) do m[i] := i;
// можно вместо Low(m) писать просто 0...
end;

Но это не динамический массив. Ответ на вопрос - нет.
К примеру, я не смогу в Proc1 написать SetLength(m, 10);
Сколько выделил памяти под m, столько и могу использовать...
Можно передать дин. массив в качестве открытого массива, также как и статический:
Код

var
 stat : array [4..11] of integer;
 dyn : array of integer;
begin
 SetLength(dyn, 20);
 Proc1(dyn);
 Proc1(stat);
end;

При передаче дин. массива передается указатель на первый элемент данных, и длина дин. массива (которая не известна на этапе компиляции).
При передаче стат. массива в качестве открытого массива длина массива сразу известна на этапе компиляции...

Автор: p0s0l 25.5.2004, 01:35
ЗЫ: Насчет статических массивов: можно схитрить насчет длины. Например, для приведенной выше процедуры можно сделать так:
Код
type PseudoP1 = procedure (Adr : pointer; Len : cardinal);
var
 stat : array [4..11] of integer;
begin
 asm push ebp end;
 PseudoP1(@Proc1)(@stat, 5);
end;

В результате, хоть и размер статического массива = 8, обработке в Proc1 пойдут только первый 6 (5+1=6) элементов... Ну это так, мало ли кому будет лень передавать еще один параметр для указания размера массива...

Автор: p0s0l 25.5.2004, 01:47
Цитата
Что такое конструктор массива и для чего он нужен?

Пример:
Код
procedure Proc1(m : array of integer);
var
 i : integer;
begin
 for i := Low(m) to High(m) do
   Form1.ListBox1.Items.Add(IntToStr(m[i]));
end;

Тут m - открытый массив. Пример вызова:
Код
var z : array [0..5] of integer;
begin
...
 Proc1(z);
end;

Пример использования конструктора:
Код
var
 a,b,c,d : integer;
begin
 ...
 Proc1([1,6,4,7,3,4,a,b,c,d]);
end;

Думаю, из примера видно что конструктор налету собирает массив.

Автор: Unregistered 25.5.2004, 02:16
Цитата(p0s0l @ 25.5.2004, 01:23)
Код

var
 stat : array [4..11] of integer;
 dyn : array of integer;
begin
 SetLength(dyn, 20);
 Proc1(dyn);
 Proc1(stat);
end;

При передаче дин. массива передается указатель на первый элемент данных, и длина дин. массива (которая не известна на этапе компиляции).
При передаче стат. массива в качестве открытого массива длина массива сразу известна на этапе компиляции...

p0s0l, чего-то не понял.... в приведенном тобой коде, в процедуру передается динамический массив без параметра его длины... А дальше ты пишешь, что надо передавать длину массива. И так ли обязательно передавать длину массива? У меня написана длл в которой реализованы такие функции:
Код

function CheckAnswer (AAnswer:array of byte):boolean;stdcall;
var TmpBuf:array of byte;
begin
 if AAnswer[0]<>1 then
 begin
   Result:=false;
   exit;
 end;
 SetLength(TmpBuf,4);
 Move(AAnswer,Pointer(TmpBuf)^,4);
 if not CheckCS(TmpBuf) then
 begin
   Result:=false;
   exit;
 end;
 if not CheckCS(AAnswer) then
  begin
   Result:=false;
   exit;
 end;
 Result:=true;
end;

и внутренняя функция длл

function CheckCS(Buff:array of byte):boolean;stdcall;//контрольная сумма, не экспортируется
var i,CS:integer;
begin
 CS:=0;
 For i:=0 to SizeOf(Buff)-2 do
   CS:=CS+Buff[i];
 While CS>255 do
   dec(CS,255);
 Result:=(CS=Buff[SizeOf(Buff)-1]);
end;


Вызывая первую функцию я передаю ей динамический массив, в CheckCS передаю и динамический массив и открытый массив - SizeOf отлично справляется (как видно нет параметра передающего длину массива). Твой ответ заставил меня задуматься, а правильно ли я это реализовал? Поясни, пожалуйста.
PS написано несколько программ с использованием этой длл, и все нормально работает.

Автор: p0s0l 25.5.2004, 09:21
Я неправильно выразился. И имел в виду, что длина массива передается неявным параметром, что я потом и показал с помощью "псевдо"-функции...

Автор: Scrip 25.5.2004, 13:43
Цитата

Пример использования конструктора:
Код

var
a,b,c,d : integer;
begin
...
Proc1([1,6,4,7,3,4,a,b,c,d]);
end;


Думаю, из примера видно что конструктор налету собирает массив.

Непонятно. Что значит конструктор налету собирает массив? Какой массив? Ведь при выполнении процедуры Proc1 не описано каким фактическим параметром заменить формальный параметр m. bored.gif

Автор: Unregistered 25.5.2004, 13:54
p0s0l, спасибо. С асмом у меня туговато.

Автор: p0s0l 25.5.2004, 14:19
Цитата
Непонятно. Что значит конструктор налету собирает массив? Какой массив?

Какой массив ? Вот такой: [1,6,4,7,3,4,a,b,c,d] - в квадратных скобках друг за другом перечислены элементы передаваемого массива...
Что значит "Налету собирает" ? Конструктор создает в стеке временный массив из перечисленных элементов, и передает указатель на него и длину (но это мы не видим), после завершения вызванной процедуры массива уже не будет... Конструктором можно пользоваться только для передачи параметров. И они не могут передаваться в качестве var-параметров (понятно почему)...
Вот два абсолютно эквивалентных примера (даже код в результате генерится одинаковый):
Код
procedure Proc1(m : array of integer);
begin
  ...
end;

var m : array [0..3] of integer;
begin
  m[0] := 0;
  m[1] := 1;
  m[2] := 2;
  m[3] := 3;
  Proc1(m);
end;

Код
procedure Proc1(m : array of integer);
begin
  ...
end;

begin
  Proc1([0,1,2,3]);
end;


Автор: Scrip 25.5.2004, 14:20
Цитата
К примеру, я не смогу в Proc1 написать SetLength(m, 10);
Сколько выделил памяти под m, столько и могу использовать...

Если "Открытый массив - массив неизвестного размера", то под m память вообще не выделена. Так? Или ... нет... не так
Добавлено @ 14:23
Все, с конструктором разобрался!

Автор: p0s0l 25.5.2004, 14:24
Цитата
Если "Открытый массив - массив неизвестного размера", то под m память вообще не выделена. Так? Или ... нет... не так

Выделена. Процедура Proc1 на этапе компиляции не знает размер массива. При выполнении же программы она в качестве дополнительного параметра (которого мы не видим) получает размер массива...

Автор: Kesh 25.5.2004, 14:30
Цитата(p0s0l @ 25.5.2004, 15:24)
При выполнении же программы она в качестве дополнительного параметра (которого мы не видим) получает размер массива...

Разве?.. Мне казалось, что получив указатель (только его)... Она уже сама определяет размер массива... Я не отрицаю того, что этот размер хранится в программе, но по-моему в процедуру он в заголовке не передается...

Автор: p0s0l 25.5.2004, 14:38
Kesh, если я тебе дам только указатель на ячейку памяти, как ты узнаешь сколько массив занимает ? Он может и 10 байт занимать, а может 10 мб...
Если я в var'е написал:
m : array [0..31] of byte;
То m займет ровно 32 байта. В памяти нигде не хранится размер этого массива...

Автор: Scrip 25.5.2004, 14:44
p0s0l, а сколько выделена? Намерняка мы этого опять незнаем sad.gif
Размер массива процедуры Proc1 равен фактичекому параметру, заменившему формальный параметр процедуры proc1. Если понял что я сказал ответь пожалста. smile.gif cool.gif

Автор: p0s0l 25.5.2004, 17:53
Ну вроди типа того... smile.gif

Автор: Kesh 25.5.2004, 20:38
p0s0l Ну дал ты мне указатель m: array of integer; Ну и что мне мешает сделать так
Код
Size := (High(m)+1)*SizeOf(Integer);

Автор: p0s0l 25.5.2004, 20:49
Kesh, ну и как же по-твоему прога узнает значение High(m) ?
Из космоса бог пошлет что ли ? Как раз этот самый High(m) и передается в качестве неявного невидимого параметра...

Автор: Kesh 25.5.2004, 21:00
А ты уверен, что он передается, а не хранится в программе?..

Автор: p0s0l 25.5.2004, 22:23
Kesh, такое ощущение, что ты надо мной издеваешься... smile.gif
В самом начале было сказано, что у открытого массива длина на этапе компиляции неизвестна. Как тогда High(m) может быть известен компилятору, если процедуре могут передать как массив из 10 элементов, так и массив из 1000 элементов ? Где этот High(m) по-твоему может хранится ? Это раз.
Во-вторых, тоже, почти в начале же выявил с помощью псевдо-функции неявный параметр, который как раз является High(m)...

Автор: Kesh 25.5.2004, 22:34
p0s0l Ничего я над тобой не издеваюсь... Мне в самом деле непонятно...
Цитата
В самом начале было сказано, что у открытого массива длина на этапе компиляции неизвестна.
Не согласен, 4байта - на указатель + ???(ну не знаю я) байт на описание типа.
Цитата
Как тогда High(m) может быть известен компилятору, если процедуре могут передать как массив из 10 элементов, так и массив из 1000 элементов ? Где этот High(m) по-твоему может хранится ? Это раз.
А по-моему он хранится в самой программе, так сказать в ее глобальной части... Ну как глобальные переменные, а вовсе не передается как скрытый параметр при вызове процедуры... ИМХО передается только ссылка, а по этой ссылке уже идет обращение к программе (к глобальному модулю), откуда и берется описание...
Цитата
Во-вторых, тоже, почти в начале же выявил с помощью псевдо-функции неявный параметр, который как раз является High(m)...
А это действительно так... Есть у меня проблема... Не верю я на слово... То, что ты написал - действительно иллюстрирует работу со статикой и динамикой... но, ИМХО, не более... Где это запостулировано, что исполняется программа именно так?..

P.S. Мне действительно интересно...

Автор: p0s0l 27.5.2004, 18:32
Цитата
Не согласен, 4байта - на указатель + ???(ну не знаю я) байт на описание типа.
Это вообще про что ? Размер указателя и размер массива - разные вещи. Откуда взялось 4 байта ? И что за описание типа ? Теперь уже мне ничего не понятно... butbut.gif
Цитата
А по-моему он хранится в самой программе, так сказать в ее глобальной части... Ну как глобальные переменные, а вовсе не передается как скрытый параметр при вызове процедуры... ИМХО передается только ссылка, а по этой ссылке уже идет обращение к программе (к глобальному модулю), откуда и берется описание...

Гм... Пример:
Код

procedure Proc1(var m : array of integer);
begin
...
end;

var
 a : array [1..10] of integer;
 b : array [1..20] of integer absolute a;

begin
 Proc1(a);
 Proc1(b);
end;

Два массива разной длины начинаются с одного и того же адреса (накладываются друг на друга).
В обоих вызовах Proc1 мы передаём указатель на одну и ту же ячейку памяти... И как процедура Proc1 определит, длину какого массива ей использовать: a и b ? Ведь по твоей гипотезе ей передается только указатель... Так что тут облом будет...
Цитата
А это действительно так... Есть у меня проблема... Не верю я на слово... То, что ты написал - действительно иллюстрирует работу со статикой и динамикой... но, ИМХО, не более... Где это запостулировано, что исполняется программа именно так?...
Не понял. Тебе надо цитату из справки Delphi привести ? Да наверное, там такого нет. Не будут они углубляться в хелпе во всякие подробности ненужные...
Ну если не веришь - проверь сам. Набери чуть выше приведенный пример. В дебаггере глянь на вызовы Proc1:
Код
lea eax, [ebp-$28]
mov edx, 9
call Proc1

lea eax, [ebp-$28]
mov edx, 19
call Proc1

lea eax, [ebp-$28] в обоих вызовах загружает в eax один и тот же адрес - начало массива a (или массива b, т.к. они наложены друг на друга).
Далее в edx засовывается макс. элемент массива (тот самый High(m)).
Далее идет вызов Proc1...

Автор: Kesh 27.5.2004, 23:31
Цитата
Откуда взялось 4 байта ?
Я думал, что именно столько занимает указатель...
Цитата
В обоих вызовах Proc1 мы передаём указатель на одну и ту же ячейку памяти... И как процедура Proc1 определит, длину какого массива ей использовать: a и b ? Ведь по твоей гипотезе ей передается только указатель... Так что тут облом будет...
Ну здесь ты вообще передаешь статические массивы... Я спрашивал про динамические... Тут вот что выдает...
Код
var
a : array of integer;
b : array of integer absolute a;

procedure Proc1(var m : array of integer);
begin
 m[0] := m[0];
end;

begin
Proc1(a);
Proc1(b);
end.

Код
Proc1(a);
mov eax, [a]
call @DynArrayHigh
mov edx, eax
mov eax, [a]
call Proc1
............
Proc1(b);
mov ebx, [a]
mov eax, ebx
call @DynArrayHigh
mov edx, eax
mov eax, ebx
call Proc1


И что по-твоему означает call @DynArrayHigh
Добавлено @ 23:36
Оно же засовывает High(m) в edx... a в Proc1 передается eax... Мне вот интересно... Ведь Proc1 берет значение из edx сама... Этот самый High берется из программы...

Автор: Girder 28.5.2004, 00:16
Как не напиши:
procedure Proc1(var m : array of integer);
или
procedure Proc1(m : array of integer);

в Proc1 - передается указатель на массив и не явно максимальный номер массима.

Если напишим:

var XXX: array [1..2] of ..
begin
...
Proc1(xxx);
...
end;
то в Proc1 - длина массива без проблемм опредилится.

А если напишим:

Type
TXXXP:array of ...
var XXX: array of ..
XXXP:^TXXXP;
n:array of ..
T:TList;
begin
SetLength(XXX,...)
...
Proc1(xxx);
...
n:=xxx;
SetLength(n,...)
...
Proc1(n);
...
T:=TList.Create;
New(XXXP);
XXXP^:=n;
T.ADD(XXXP);
...
XXX:=T.Items[...];
...
Proc1(xxx);
...
end;

то в Proc1 - при определении длины массива случаются осечки.

По этому лудше всегда дополнительно указывать явно максимальное значение массива, т.е:
procedure Proc1(var m : array of integer;IMax:integer);

Автор: p0s0l 28.5.2004, 01:04
Kesh, ты хоть представляешь о чем речь идёт ? Я тебе об одном, а ты оказывается совсем о другом...
Я сказал, что при передаче массива в качестве отрытого массива процедуре Proc1 передаётся:
1) Адрес начала данных
2) № макс. элемента массива (High(m)) (неявно)
И далее дискуссия шла именно об этом.
Я тебе привел пример со статическим массивом. А ты - с динамическим:
Цитата
mov ebx, [a]
mov eax, ebx
call @DynArrayHigh
mov edx, eax

mov eax, ebx
call Proc1

Как видишь, DynArrayHigh вызывается перед вызовом Proc1, а не в самой Proc1. Далее идёт:
Цитата
но же засовывает High(m) в edx... a в Proc1 передается eax...

А edx КУДА передаётся ??? Он идёт туда же в Proc1, и если в процедуре Proc1 встретится High(m), то будет использоваться значение edx.
Как ни крути, но ты сам щас доказал, что передается адрес массива (eax) и длина массива (edx)...

Я так понял, ты пытаешься доказать, что длина динамического массива хранится где-то в ОП. Зачем мне это доказывать ? Я и так с тобой бы согласился... Но длина статического массива всё же нигде не хранится...

Girder, если вместо
Код
XXX:=T.Items[...];
...
Proc1(xxx);
поставить:
Код
 XXXp:=T.Items[0];
 Proc1(xxxp);

то всё ок будет, т.к. ты пытался сделать что-то не очень понятное (указатель присвоить массиву, в итоге компилятор решил вообще ничего не делать с xxx). Или же так:
Код
type txxxpp = ^txxxp;
...
XXX:=txxxpp(T[0])^;
Proc(xxx);

Автор: Girder 28.5.2004, 03:04
Код
XXXp:=T.Items[0];
Proc1(xxxp);

Это и имелось в виду! Просто ошибся.

И я не спорю с тобой, а стараюсь разъяснить.

Когда то я тоже писал вот-так:
-procedure Proc1(var m : array of ...);
или(кто как хочет пускай и пишит)
-procedure Proc1(m : array of ...);

Но в один прекрасный момент сталкнулся с проблеммой
не правильного определения размера массива в
exclamation.gif вызываемой exclamation.gif процедуре.
Не спорю - это могло произойти только на моем компьютере,
в данном версии компилятора, в это утро, при этом расположении планет и т.п. хрень - но это произошло(а за много лет программирования в Delphi не первый раз сталкнулся с этой проблеммой)

Автор: p0s0l 28.5.2004, 03:14
Цитата
не правильного определения размера массива в
вызываемой  процедуре.

Странно это. Тем более что было сказано, что не в вызываемой процедуре определяется размер массива, а в вызывающей...
Всё равно, интересно было бы взгянуть на это, но это, как понимаю, единственный случай, и его теперь не воссоздать.
Но суть не в этом. Эта проблема не открытого массива, а твоя проблема. Или проблема TList'а, или чего там использовал.
Ведь в твоем примере, если сделать так:
Код
XXX:=T.Items[...];
// Proc1(xxx); уберем вызов этой функции, чтобы не отвлекала
for i := 0 to High(X) do XXX[i] := i;

И тут бы всплыла точно та же проблема у тебя. Без всяких передач массива в другую процедуру. Потому что ошибка определения длины происходит тут, а не там (в вызываемой процедуре).
(В данном случае вообще ошибки не происходит, просто делается не то что хотелось...)

Автор: Girder 28.5.2004, 03:24
Код
XXX:=T.Items[...];
// Proc1(xxx); уберем вызов этой функции, чтобы не отвлекала
for i := 0 to High(X) do XXX[i] := i;

О... с этим я сталкнулся еще раньше.

Цитата
Странно это

Ни чё, зато заставляет быть более предусмотрительным при написании
программы.

Цитата
Всё равно, интересно было бы взгянуть на это, но это, как понимаю, единственный случай, и его теперь не воссоздать.

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

Автор: p0s0l 28.5.2004, 03:37
Цитата
Ни чё, зато заставляет быть более предусмотрительным при написании
программы.

Я говорил, что странно то, что у тебя размер неправильно определялся в вызываемой процедуре. Хотя определяется-то он в вызывающей... Ну да ладно... Всё равно без багов никуда. Хотя многие баги при ближайшем рассмотрении оказываются и не багами...

Автор: Girder 28.5.2004, 04:05
Цитата
Хотя определяется-то он в вызывающей

Абсолютно верно! Кто с этим спорит!

см.выше:
Цитата
в Proc1 - передается указатель на массив и не явно максимальный номер массима.

Автор: Kesh 27.5.2004, 19:56
p0s0l Да ничего я не пытался тебе доказать... Мне просто интересно стало... Вот торкнуло меня на передачу параметров и все тут... Сейчас вот действительно склоняюсь к твоим словам... Просто до послееднего момента у меня была мысль, что параметр для edx, тот который @DynArrayHigh, cоздается в самой программе при инициализации, а там уже хранится как переменная... Переубедил... Респект...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)