Как задать нижнюю границу массива динамически?
Модератор: Модераторы
AlphaBlend
Не обращайте внимания, ему нужно действительно использовать что, то типа TList. Возможно мы не понимаем сути его задачи. На моей практике это часто бывает. Пусть сам разбирается.
Не обращайте внимания, ему нужно действительно использовать что, то типа TList. Возможно мы не понимаем сути его задачи. На моей практике это часто бывает. Пусть сам разбирается.
vvvchты реально до сих пор не понял "сути задачи"? Открой глаза, прочитай название темы, в которую пишешь. Если это не стеб, то ситуация просто клиническая.
AlphaBlend писал(а):Вам не только на блюдечке все п одали выше , но еще и салфеточку повязали и даже разжевали
И не только выше, на форуме точно такая же тема поднималась совсем недавно.
CRobin
Во первых, не "тыкай" мне, я на Вы разговаривал. Во-вторых если просишь помощи, научись не хамить!
Во первых, не "тыкай" мне, я на Вы разговаривал. Во-вторых если просишь помощи, научись не хамить!
vvvch при столь очевидной и простой формулировке задачи вас не беспокоит, что вы до сих пор ее не поняли, исписав две страницы ответов. Зато беспокоит что я обращаюсь к вам на "ты". Это поразительно.
CRobin а может это Вы чего-то не понимаете, что Вам хотят сказать? (Что более вероятно!) Ну ничего, со временем дойдёт...
CRobin писал(а):скалогрыз не уверен, но есть ощущение, что такое все же можно сделать через динамические константы и указатели. В случае с объектом я не могу передать указатель на конкретное поле записи, насколько я понимаю, по типу такого
Объект использовать не обязательно, но очень удобно, т.к. он прячет (инкапсулирует) дополнительные переменные, необходимые для отслеживания нижней границы, а так же всю рутину которая возникает в случае изменения нижней границы.
Указатель получить на конкертное поле записи можно:
Код: Выделить всё
type
TEntryArray = class(TObject)
...
function GetElementPtr(i: integer): PEntry;
end;
function TEntryArray.GetElementPtr(i: integer): PEntry;
begin
//todo: sanity check, return nil, if i is invalid
Result:=@data[i-flow];
end;
на выходе получаем код:
Код: Выделить всё
e := @data.GetElementPtr(i)^.field;
может быть не очень красиво, но зато работает. Тут можно ещё задаться вопросом что это за тип такой TEntry.
(Кстати, отличный пример, где дженерики хорошо бы подошли, Дож
Если TEntry это какой-нить record, то следует помнить, что GetLEmentPtr вернёт указатель на элемент. И указатель будет правильным, но только до следующего изменения нижней границы.
скалогрыз адрес элемента массива в памяти можно найти отсчитав от адреса массива i*SizeOf(TEntry), затем, имея адрес можно получить значение. Что и происходит, при обращении к элемента массива по индексу начинающемуся с 0. Но в случае, если массив объявлен статически с использованием перечисления или через указание интервал [A..B], тогда так не получается. Это означает, что где то в памяти находится значение "отступа", которое равно А. Вопрос - можно ли изменить в памяти это значение А для того чтоб сделать в индексе смещение? Например задав компилятору определенные директивы, которые позволят вмешиваться в способ хранения массива.
CRobin писал(а):Но в случае, если массив объявлен статически с использованием перечисления или через указание интервал [A..B], тогда так не получается. Это означает, что где то в памяти находится значение "отступа", которое равно А.
нет, именно так и получается. В памяти значние "A" для статических массивов не хранится - это лишний расход памяти.
Во время компиляции, компилятор знает об отступе "A", и все обращения к статическому массиву преобразуются с учётом этого отступа.
Например
Код: Выделить всё
procedure Test;
var
a: array [2..4] of integer;
begin
a[2]:=5;
a[3]:=6;
writeln(a[3]);
end;
begin
Test;
end.
В коде написано writelN(a[3]);
А на самом деле компилятор преобразует этот вызов в writeln(a[1]);... потому что для компилятора массив [2..4] (условно) становится [0..2].
Значение "А" так же не хранится для динамических массивов - они просто всегда начинаются с 0.
Дополнительных директив для управления начальным индексом массива нет.
Рекомендую скомпилировать следующий код, с директировой -al, чтобы получить ассебмлерный код. И сравнить процедуры Test и Test2
Код: Выделить всё
procedure Test;
var
a: array [2..4] of integer;
begin
a[2]:=5;
a[3]:=6;
writeln(a[3]);
end;
procedure Test2;
var
a: array [0..2] of integer;
begin
a[0]:=5;
a[1]:=6;
writeln(a[1]);
end;
begin
Test;
Test2;
end.
скалогрыз писал(а):Во время компиляции, компилятор знает об отступе "A", и все обращения к статическому массиву преобразуются с учётом этого отступа.
Все так. Но ведь обращение к элементу по индексу я могу делать, например, вводя ключ с клавиатуры. Компилятор не знает что именно я введу, а это значит ему нужно будет отнять отступ А для того чтоб получить нужный элимент, иначе никак. Это значит, что где то в памяти все же этот отступ хранится.
Добавлено спустя 6 минут 53 секунды:
раньше Паскаль поддерживал такой синтаксис
Код: Выделить всё
type TMyArray(a,b:integer) = array [a..b] of elem;
var PMyArray = TMyArray(222,333);
правильно ли я понимаю что уже это не возможно?
CRobin писал(а):Компилятор не знает что именно я введу, а это значит ему нужно будет отнять отступ А для того чтоб получить нужный элимент, иначе никак. Это значит, что где то в памяти все же этот отступ хранится
Он не хранится в памяти, отступ А будет внесён непосредственно в код обращения к элементу.
Вот код.
Код: Выделить всё
{$mode delphi}
uses Classes, SysUtils;
var
a: array [10..20] of integer;
s: string;
i: integer;
k: integer;
begin
for i:=low(a) to high(a) do
a[i]:=i;
readln(s);
while s<>'' do begin
i:=StrToIntDef(s,-1);
if (i>=low(a)) and (i<=high(a)) then begin
k:=a[i];
writeln(k);
end;
readln(s);
end;
end.
Компилируем с ассемблером (fpc -as -Amasm test.pas)
Результат:
Код: Выделить всё
; [16] k:=a[i];
mov eax,dword ptr [U_P$PROGRAM_I]
mov eax,dword ptr [U_P$PROGRAM_A+eax*4-40]
mov dword ptr [U_P$PROGRAM_K],eax
на (не)человечьем языке это звучит так
1) возьми переменную I
2) помнож значение на 4, и вычти 40 (размер integer-а - это 4 байта, а массив начинается с 10-го элемента. 4*10 = 40)
3) возьми 4-х байтное значение по указанному отступу и запиши в переменную K.
Отступ "А" - стал частью кода, а не отдельной переменной в памяти.
как я уже писал в другой теме, массивы вещь - низкоуровневая. Очень удобная для внутренней реализации, но не всегда подходит в качестве интерфейса
Добавлено спустя 6 минут 16 секунд:
CRobin писал(а):раньше Паскаль поддерживал такой синтаксис
а раньше это когда?
скалогрыз писал(а):а раньше это когда?
последний раз на нем писал когда у меня был 486dx
CRobin писал(а):последний раз на нем писал когда у меня был 486dx
возможно. А что за паскаль такой?
На моём 486, Turbo Pascal 7.0 и 5.0 такого не разрешали.
я точно знаю, как такое можно на Си написать!
Может какой-нить Mircosoft Pascal?
Последний раз редактировалось скалогрыз 06.07.2016 21:40:39, всего редактировалось 1 раз.
CRobin
Больны какраз вы. Лекарство в постах скалогрыз
Код: Выделить всё
const a = 22222222222222;
b = 22222222222333;
var dic : array[a..b] of TEntry;
Больны какраз вы. Лекарство в постах скалогрыз
