Czy da się, ale bez pośrednich konwersji, zrobić tak, żeby procedura Foo przyjęła jako parametr typ PGrid (tablicę wskaźników wskazujących na Integer), zamiast zwykłego TGrid (zawierającego po prostu integery)?
No ale co chcesz przerobić? Masz procedurę, która jest zadeklarowana w taki sposób, że jako parametr przyjmuje wyłącznie dynamiczną macierz liczb, więc tylko taką macierz możesz do niej przekazać.
Poza tym Twój przykład procedury Foo
przedstawia sposób przekazywania macierzy najwolniejszy ze wszystkich możliwych. Jeśli zależy Ci na efektywności, to zawsze przekazuj macierze przez referencję (ciągi znaków i duże struktury również). Z dowolnym modyfikatorem – const
, var
lub out
– bo każdy z nich oznacza wewnętrzne przekazanie nie całego bloku danych, a wskaźnika na taki blok. Parametr bez żadnego modyfikatora to przekazanie kopii danych, a im więcej tych danych, tym dłużej trwa ich klonowanie.
Wracając do problemu – przepisz kod obecnej procedury (tej która przyjmuje całą macierz w parametrze) na taką, która przyjmuje w nim wskaźnik na macierz i na tym wskaźniku operuje. Dzięki temu będziesz mógł z niej skorzystać zarówno mając wskaźnik na macierz (po prostu go podając w parametrze), ale też mając tablicę (podając w parametrze adres tej tablicy, korzystając z operatora @
).
Dodatkowo, jeśli koniecznie potrzebujesz mieć procedurkę pobierającą całą macierz (a nie jej wskaźnik), to napisz sobie wrapper na tę pobierającą wskaźnik. Przykład niżej:
type
TMyArray = array of Integer;
PMyArray = ^TMyArray;
// właściwa procedura przetwarzająca macierz na podstawie wskaźnika
procedure DoSomeStuff(AArray: PMyArray); overload;
// wrapper na tę właściwą, operujący na macierzy
procedure DoSomeStuff(var AArray: TMyArray); overload;
{..}
procedure DoSomeStuff(AArray: PMyArray);
begin
// operacje na macierzy
end;
procedure DoSomeStuff(var AArray: TMyArray);
begin
DoSomeStuff(@AArray); // wywołanie właściwej procedury
end;
A jeśli już koniecznie musisz mieć tylko jedną procedurkę, która przyjmuje macierz a nie wskaźnik, to też możesz z niej skorzystać, nawet jeśli masz tylko wskaźnik do macierzy. Przykład:
type
TMyArray = array of Integer;
PMyArray = ^TMyArray;
procedure DoSomeStuff(var AArary: TMyArray);
var
Value: Integer;
begin
for Value in AArary do
Write(Value:2);
WriteLn();
end;
var
MyArray: TMyArray;
PtArray: PMyArray;
begin
MyArray := TMyArray.Create(0, 2, 4, 8); // utworzenie macierzy
PtArray := @MyArray; // pobranie adresu do zmiennej wskaźnikowej
{..}
DoSomeStuff(PtArray^); // przekazanie macierzy za pomocą wskaźnika
ReadLn();
end.
Testowane we Free Pascalu – nie wiem czy Delphi na to pozwala (powinno).
Przy okazji:
type
TGrid = array of Integer;
PGrid = array of ^Integer;
Tak się nie tworzy wskaźnika na macierz. Twój PGrid
w dalszym ciągu jest zwykłą macierzą dynamiczną, ale zamiast przechowywać liczby, przechowuje wskaźniki na liczby. Z tego względu po pierwsze będziesz musiał ręcznie ustalać rozmiar mecierzy (w końcu jest dynamiczną), a po drugie, będziesz musiał ręcznie alokować i dealokować pamięć dla każdej jej komórki. Obsługa takiej macierzy będzie trudna – niepotrzebnie komplikujesz sobie robotę.
Z nazewnictwa tych dwóch typów wnioskuję, że chcesz mieć wskaźnik na macierz, a nie macierz wskaźników, dlatego zobacz w przykładach wyżej jak powinna wyglądać deklaracja tych typów.