2016-03-17 3 views
2

Я немного застрял. Я хочу, чтобы иметь массив так:Массив с отрицательным индексом во время выполнения

Array [-3..Index, 1..otherIndex] of Integer;

Но мне также нужно инициализировать этот массив на время выполнения, на основе заданных параметров. Так что Index и otherIndex не установлены в начале.

Я думаю, что я не могу инициализировать отрицательный индекс в динамическом массиве, но как бы инициализировать такой статический массив во время выполнения?

+1

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

+0

Эта декларация придерживается правила постоянного выражения (см. Документы). –

ответ

4

Вы переносите массив внутри записи.

type 
    TMyArray = record 
    private 
    FData: array of integer; 
    ..... 
    public 
    class function New(Size1, Size2: cardinal): TMyArray; static; 
    function Free; //only needed if you utilize GetMem. 
    property Item[x, y: integer]: integer read GetItem write SetItem; default; 
    end; 

В функции New вы используете SetLength для инициализации массива.
SetLength(Result.FData, SizeX*SizeY).

в GetItem/SetItem пары вы добавляете 3 к x индексу/вычесть 1 из индекса y и, таким образом, получить доступ к реальному массиву, который начинается с 0.

GetMem
Другим способом заключается в использовании GetMem выделить блок памяти.
Обратите внимание, что GetMem не нулевой памяти, поэтому, если вы хотите инициализировать нулевой массив, вам нужно позвонить ZeroMemory, чтобы очистить буфер. GetItem тогда выглядит следующим образом:

{$pointermath on} 

TMyArray = record 
private 
    FData: PInteger; 
    FSizeX, FSizeY: cardinal; //The size of the array. 
    ..... 

//You can use the same code for dynarray and GetMem. 
function TMyArray.GetItem(x,y: integer): integer; 
begin 
    //Inc(x,3); Dec(y,1); 
    Result := FData[(x+3)+(y-1)*FSizeX]; 
end; 

Поскольку Item является свойством по умолчанию, вы можете просто написать i := MyArray[-3,2];

Cleanup
При использовании динамических массивов будет Delphi очистки памяти для вас автоматически, когда запись выходит за рамки.
Если вы используете GetMem, вам придется выполнять свою очистку.

Однако вы можете добавить автоматическую очистку/деструктор, используя интерфейс в трюке записи, см. here и here.

+0

Im получает «E2124», когда я пытаюсь получить доступ к FData в новом методе. Директива по умолчанию не имеет значения в типе записи, это, по крайней мере, то, что говорит мой компилятор. – Vollmilchbb

+0

@Vollmilchbb: Новая функция должна быть закодирована как _SetLength (Result.FData, FSizeX * FSizeY) _. Поскольку это статическая функция, у вас нет «_Self_», а результатом функции является новый массив, который вам нужно выделить. – HeartWare

+0

'функция TMyArray.GetItem (x, y: integer): integer; начало Результат: = FData [(x + 3) + (y-1) * FSizeX]; end; 'дает компилятору больше шансов на успешную оптимизацию. Я подозреваю, что –

0

Если у вас есть нижняя граница (например, -высокие (SMALLINT)) вы можете сделать следующее:

type 
    TNegIntArr = Array[-High(SmallInt)..High(SmallInt)] of Integer; 
    PNegIntArr = ^TNegIntArr; 


procedure use(numNeg : integer; arrLen : integer); 
var buf : TIntegerDynArray; 
    arr : PNegIntArr ; 
begin 
    SetLength(buf, arrLen); 
    arr := @buf[numNeg]; 

    dec(PByte(arr), Cardinal(@arr ^[0]) - Cardinal(@arr^[Low(TNegIntArr)]); 

    // you can now savely access the array: 
    for counter := -numNeg to arrLen - numNeg - 1 do 
     arr^[counter] := counter; 
end; 

Это вполне оптимально с вычислительной точки зрения (без вызовов процедур), но и является бит опасен, поскольку проверка диапазона не включена.

+0

Есть много более чистых опций, которые не требуют вызовов функций –

Смежные вопросы