Как Вы передаете массив ссылкой в Delphi?

Reduce(function(x, y) x + replace(y, is.na(y), 0), mylist)/
    Reduce(`+`, lapply(mylist, function(x) !is.na(x)))
#  x   y
#1 2 3.5
#2 3 4.0

ИЛИ

nm = c("x", "y")  # could do `nm = names(mylist[[1]])`
sapply(nm, function(NM)
    rowMeans(do.call(cbind, lapply(mylist, function(x) x[NM])), na.rm = TRUE))
#     x   y
#[1,] 2 3.5
#[2,] 3 4.0
11
задан mghie 3 April 2009 в 16:27
поделиться

2 ответа

При передаче динамического массива как параметра не-var компилятор сделает копию.

Маленький пример кода ниже демонстрирует это путем отображения 37/42 в подписи формы.

procedure IncArray1(data: array of integer);
var i : integer;
begin
  for i := Low(data) to High(data) do
    data[i] := data[i] + 5;
end;

procedure IncArray2(var data: array of integer);
var i : integer;
begin
  for i := Low(data) to High(data) do
    data[i] := data[i] + 5;
end;

procedure TForm8.FormCreate(Sender: TObject);
var
  data: array of integer;
begin
  SetLength(data, 1);
  data[0] := 37;
  IncArray1(data);
  Caption := IntToStr(data[0]);
  IncArray2(data);
  Caption := Caption + '/' + IntToStr(data[0]);
end;

Если мы изучаем сгенерированный ассемблерный код, IncArray1 запускается с

004552B4 8BCA             mov ecx,edx
004552B6 85C9             test ecx,ecx
004552B8 7807             js $004552c1
004552BA 8B1C88           mov ebx,[eax+ecx*4]
004552BD 49               dec ecx
004552BE 53               push ebx
004552BF 79F9             jns $004552ba
004552C1 8BC4             mov eax,esp

Этот код копирует исходный массив в стек и устанавливает eax на адрес первого элемента (= адрес, сохраненный в указателе вершины стека после последнего нажатия). Стек углубляется так, код запускается с последнего элемента (edx, содержит Высокий (данные), когда IncArray1 называют) и повторения (элемент чтения; продвиньте элемент; постепенно уменьшите индекс), пока это не доберется до элемента 0.

IncArray2 не содержит такого кода. Вызывающая сторона хранит адрес данных в регистр eax прежде, чем назвать IncArray2, и IncArray2 просто использует этот адрес.

В случае, если Вы не хотите использовать 'var' по любой причине, можно передать адрес данных к методу. Но поскольку Вы не можете использовать синтаксис 'данные: ^array целого числа' в объявлении параметра, необходимо было бы объявить тип для данных. И необходимо было бы использовать 'data^' вместо 'данных' везде в методе.

type
  TData = array of integer;
  PData = ^TData;

procedure IncArray(data: PData);
var i : integer;
begin
  for i := Low(data^) to High(data^) do
    data^[i] := data^[i] + 5;
end;

procedure TForm8.FormCreate(Sender: TObject);
var
  data: TData;
begin
  SetLength(data, 2);
  data[0] := 37;
  IncArray(@data);
  Caption := IntToStr(data[0]);
end;

Протестированный с Delphi 2007.

25
ответ дан 3 December 2019 в 02:41
поделиться

Ответ Gabr корректен, но ключевой пункт прокладывается под землей достаточно глубоко, что я произведу его как отдельное сообщение:

Определите свои типы сначала! В этом конкретном случае компилятор принял массив целого числа там, но это - то, только потому, что это имеет особое значение, и это не то, что Вы ожидали. Любая другая попытка определить тип в определении процедуры просто перестала бы работать.

В отличие от C, если Вы хотите две вещи быть присвоением, совместимым, необходимо объявить их как являющийся ТЕМ ЖЕ типом, не просто двумя типами, которые создаются то же:

Var
     A : Array [1..4] of Integer;
     B : Array [1..4] of Integer;

Begin
    A := B;

Не скомпилирует. Скорее:

Type
    Array4 = array [1..4] of Integer;

Var
    A : Array4;
    B : Array4;

Begin
    A := B;

и компилятор делает то, что Вы ожидали бы.

6
ответ дан 3 December 2019 в 02:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: