Programowanie w języku Delphi » Gotowce

Samoalokująca tablica. Tablice dynamiczne. / Self-allocating array. Dynamic arrays.

Uwaga:
Jeśli nie chcesz tego czytać, a zobaczyć, jak to działa, pobierz pełny spakowany (.zip) projekt Delphi z kodem źródłowym, klikając tutaj SelfAllocArr.zip (233,58 KB)
Uwagi do projektu (prototypowego) na końcu tego artykułu.

Note:
If you do not want to read it, but you want to see how it works, download full zipped Delphi project with enclosed source code by clicking here  SelfAllocArr.zip (233,58 KB)
Notes to project (prototype) at the end of this article.

WstępIntroduction
Panie Protasewicz, czy jak pan chce zaorać pole, to musi pan używać czołgu?

Jeden z moich wykładowców
Mr. Protasewicz, or how you want to plow the field, then you must use a tank?

One of my lecturers
Jak stworzyć tablicę, która sama będzie dopasowywała rozmiar do indeksu, którego użyję, tzn. nie trzeba będzie deklarować jej rozmiaru na początku? Pascal jest bardzo restrykcyjny, ale na szczęście w Delphi są tablice dynamiczne. Chciałem to zrobić w bardzo uniwersalny sposób, jednak okazało się, że czasami w optymalizacji najlepszą metodą jest dychotomia. Inteligentna metoda nie pomoże, kiedy liczy się czas wykonania zadania. Więc zdecydowałem się zrobić kilka mniejszych zadań dla 1, 2, 3, 4-wymiarowych tablic. Nie sądzę, żebyś kiedyś spotkał więcej niż 4-wymiarową tablicę w zwykłej praktyce programistycznej.How to create an array that will fit the same size to the index, which I use, that does not need to declare its size at the beginning? Pascal is very restrictive, but fortunately there were dynamic arrays in Delphi. I wanted to do it in a very universal way, but it turned out that sometimes the best way to optimize is the dichotomy. Intelligent method does not help when the time counts for the task. So I decided to do some minor tasks for 1, 2, 3, 4-dimensional arrays. I do not think you ever met more than a 4-dimensional array in ordinary programming.
W zależności od użytych indeksów tablica sama przyjmie odpowiedni rozmiar - wymagane jest tylko określenie typu: jedno-, dwu-, trzy- czy czterowymiarowa (w mojej praktyce spotkałem najwyżej tablice trójwymiarowe). Tablica (indeksowana od zera) jest zbiorem elementów typu Variant, co jeszcze zwiększa jej elastyczność. Należy ją utworzyć metodą Create, a zwalniać metodą Destroy (twój program zwolni ją na końcu procedury, w której została zadeklarowana) lub przy zamknięciu programu. Można też użyć metody Clear, która zwolni z pamięci wszystkie elementy tablicy, jednak nie zniszczy jej jako obiektu.Depending on used indexes the array will set its size to necessary one – you must decide about the type only: one-, two-, three-, or four-dimmensional (in my prctice I have used maximium three-dimmensional arrays). The array (zero-base indexed) is the set of values of type Variant, what does give its greater flexibility. You must use method Create to establish one, and free it using Destroy method (your program will free the allocated array at the end of procedure being its scope of declaration) or during the end of program. You could use the method Clear, which free all allocated values of the array, but the object will still exist.
Typ Variant i koncepecja alokacjiVariant type and allocation concept
Typ Variant jest idealny do tego, by nie deklarować typów danych oprócz niego samego. Moja tablica jest jak lista, drzewo albo las, w którym mogą występować różne typy danych. Przy czym wszystkie te struktury są bardzo niewygodne w użyciu w przeciwieństwie do tablicy. Moja tablica też oszczędza pamięć - alokuje tylko indeksy od zera do maksymalnego użytego w programie i tak się dzieje we wszystkich wymiarach, co pokazuje rysunek poniżej. Typ Variant jest również na tyle wygodny, że coś, co nie zostało wcześniej podstawione daje się odczytać jako 0 lub pusty string, a zadbałem o to, żeby z rozmiarami tablic wszystko było w porządku. W debuggerze możesz zobaczyć coś takiego, jak Unassigned. Ale można to odczytywać jako 0 lub pusty string.Variant type is the ideal not to declare data types except Variant. My array is like a list, tree or forest, where there may be different types of data. At the same time, all these structures are very awkward to use, in contrast to the array. My array also saves memory - allocates only indexes from zero to the maximum used in the program and this happens in all dimensions, as shown in the figure below. Variant type is also comfortable enough that something has not previously been assigned can be read as a 0 or an empty string, and I made sure that the size of the array was in order. In the debugger you can see something like Unassigned. But it can be read as a 0 or an empty string.
Ważną jej cechą jest to, że tworzy tylko niezbędne wektory np.:An important feature is, that the only necessary vectors are created eg.:
A[2, 3] := 15
A[2, 3] := 15
zaalokuje 6 bajtów
(0, 0, (0, 0, 0, 15))
a nie - 12 bajtów (dokładniej mówiąc zamiast zer pojawią się wartości Unassigned)
((0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 15))
will alloc 6 bytes only
(0, 0, (0, 0, 0, 15))
but not a 12 bytes (preciselly in places of zeros there will Unassigned values appeare)
((0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 15))
Do niezainicjowanych pól można się odwoływać bez obawy o działanie programu:You can call not initiated fields (cells) being not afraid of program errors:
odwołanie (do nieistniejącego elementu A[5, 7]) - string1 := A[5, 7] - spowoduje zaalokowanie elementu A[5, 7] i podstawienie pod string1 wartości (pusty string).Getting (the non-existent element A[5, 7]) – string1 := A[5, 7] will cause allocating element A[5, 7] and will assign string1 the empty string.
odwołanie (do nieistniejącego elementu A[6, 8]) - int1 := A[6, 8] - spowoduje zaalokowanie elementu A[6, 8] i podstawienie pod int1 wartości 0.Getting (the non-existent element A[6, 8]) – int1 := A[6, 8] – will allocate element A[6, 8] and assign int1 value 0.
etc.etc.
Samoalokująca tablica przeznaczona jest raczej dla doświadczonych programistów, którym nieobcy jest debugger, ponieważ wykrycie błędów w indeksach i błędów w typach danych jest trudne.Self-resizing array is dedicated to advanced programmers rather, to whom the debbugger is well known, because finding errors in the indexes and data types is difficult.
Konwersje w typie VariantConversion in Variant type
Wszystkie typy całkowite, zmiennoprzecinkowe i boolowskie oraz niektóre przypadki string są kompatybilne, jeśli chodzi o podstawienia, z typem Variant, co obrazuje poniższy przykład.All integer, floating-point and boolean types and some cases of strings are compatibile, if you mean assignment to type Variant, what is shown in the example below.

Przykład / Example


var
  v1, v2, v3, v4, v5: Variant;
  i: integer;
  d: double;
  s: string;
begin
  v1 := 1;              { wartość integer / integer value                                         }
  v2 := 1234.5678;      { wartość real / real value                                               }
  v3 := 'Hello world!'; { wartość string / string value                                           }
  v4 := '1000';         { wartość string / string value                                           }
  v5 := v1 + v2 + v4;   { wartość real 2235.5678 / real value 2235.5678                           }
  i  := v1;             { i = 1 (wartość integer) / i = 1 (integer value)                         }
  d  := v2;             { d = 1234.5678 (wartość real) / d = 1234.5678 (real value)               }
  s  := v3;             { s = 'Hello world!' (wartość string) / s = 'Hello world!' (string value) }
  i  := v4;             { i = 1000 (wartość integer) / i = 1000 (integer value)                   }
  s  := v5;             { s = '2235.5678' (wartość string) / s = '2235.5678' (string value)       }
end;


Tabela konwersji / Table of conversion

Typ źródłowyTyp docelowyKonwersjaConversion
Source typeDestination type
integerrealinteger na realinteger to real
integerstringIntToStrIntToStr
integerboolean0 na false, pozostałe na true0 to false, others to true
realintegerRoundRound
realstringFloatToStrFloatToStr
realboolean0 na false, pozostałe na true0 to false, others to true
stringintegerStrToInt, może spowodować wyjątekStrToInt, possible exception occurrence
stringrealStrToFloat, może spowodować wyjątekStrToFloat, possible exception occurrence
stringboolean'false' na false, 'true' na true (nie zależy od wielkości znaków), może spowodować wyjątek'false' to false, 'true' to true (not case-sensitive), possible exception occurrence
booleanintegerfalse na 0, true: ustawia wszystkie bity na 1 (np. integer = -1, byte = 255)false to 0, true: sets all bits to 1 (eg. integer = 1, byte = 255)
booleanrealfalse na 0, true na 1false to 0, true to 1
booleanstringfalse na 'False', true na 'True' (wielkość liter zależy od ustawień środowiska)false to 'False', true to 'True' (character case depentant on environment settings
UnassignedInteger00
Unassignedstring(pusty string)(empty string)
Unassignedbooleanfalsefalse

  • Konwersja typu char dokonywana jest tak jak dla typu string
  • Conversion of type char is done like for type string string
Jak tutaj działa alokacja?How does allocation work in this case
Można tu albo wcale nie wstawiać komentarzy albo rozpisywać się bez końca.One could put here no comments either write endless comments
Dla lepszego zobrazowania o co tu chodzi posłużę się zdaniem:I will say what is below so that you could understand it better:
"Tu się nic nie dzieje niepotrzebnie.""Anything is going here unnecessarily."
i poniższym obrazkiem pokazującym 3 kolejne alokacje dla tej samej tablicy trójwymiarowejand the following picture showing 3 succesive allocations for the same three-dimensional
(Uwaga: elementy, których nie widać nie istnieją, natomiast elementy, które widać jako puste prostokąty mają wartość Unassigned):(Note: boxes which are not visible doesn't exist, and the boxes which are empty are Unassigned):


Słownik dla obrazka poniżejVocabulary for picture below
PolskiEnglish
Tablica[...]Array[...]







Interfejs / Interface

unit UAutoAllocArray;
 
uses
  Variants;
 
type
  TAutoAllocArrayDim1 = class(TObject) //tablica jednowymiarowa
                                       //one-dimensional array
    private
      FArr1: array of Variant;
      function  GetArr(aIndex: integer): Variant;
      procedure SetArr(aIndex: integer; aValue: Variant);
      procedure ReDim (aIndex: integer);
    public
      CannotAlloc: boolean; //jeśli true, alokacja się nie powiodła (zwykle
                            //przekroczono 2GB)
                            //
                            //if true, allocation failed (ussualy 2GB
                            //overallocated means over type capacity)
      procedure    Clear;
      property     Arr[aIndex: integer]: Variant
                     read GetArr write SetArr; default;
            //ponieważ użyto default można się odwołać np. A[5] := 1, a nie
            //A.Arr[5] := 1
            //
            //because of use of the 'default' directive you can call eg.
            //A[5] := 1, and you do not need A.Arr[5] := 1
      constructor  Create;
      destructor   Destroy; override;
  end;
 
type
  TAutoAllocArrayDim2 = class(TObject) //tablica dwuwymiarowa
                                       //two-dimensional array
    private
      FArr2: array of array of Variant;
      function  GetArr(aIndex1, aIndex2: integer): Variant;
      procedure SetArr(aIndex1, aIndex2: integer; aValue: Variant);
      procedure ReDim (aIndex1, aIndex2: integer);
    public
      CannotAlloc: boolean; //jeśli true, alokacja się nie powiodła (zwykle
                            //przekroczono 2GB)
                            //if true, allocation failed (ussualy 2GB
                            //overallocated means over type capacity)
      procedure    Clear;
      property     Arr[aIndex1, aIndex2: integer]: Variant
                     read GetArr write SetArr; default;
            //ponieważ użyto default można się odwołać np. A[5, 6] := 1, a nie
            //A.Arr[5, 6] := 1
            //
            //because of use of the 'default' directive you can call eg.
            //A[5, 6] := 1, and you do not need A.Arr[5, 6] := 1
      constructor  Create;
      destructor   Destroy; override;
  end;
 
type
  TAutoAllocArrayDim3 = class(TObject) //tablica trójwymiarowa
                                       //three-dimensional array
    private
      FArr3: array of array of array of Variant;
      function  GetArr(aIndex1, aIndex2, aIndex3: integer): Variant;
      procedure SetArr(aIndex1, aIndex2, aIndex3: integer; aValue: Variant);
      procedure ReDim (aIndex1, aIndex2, aIndex3: integer);
    public
      CannotAlloc: boolean; //jeśli true, alokacja się nie powiodła (zwykle
                            //przekroczono 2GB)
                            //
                            //if true, allocation failed (ussualy 2GB
                            //overallocated means over type capacity)
      procedure    Clear;
      property     Arr[aIndex1, aIndex2, aIndex3: integer]: Variant
                     read GetArr write SetArr; default;
            //ponieważ użyto default można się odwołać np. A[5, 6, 2] := 1, a
            //nie A.Arr[5, 6, 2] := 1
            //
            //because of use of the 'default' directive you can call eg.
            //A[5, 6, 2] := 1, and you do not need A.Arr[5, 6, 2] := 1
      constructor  Create;
      destructor   Destroy; override;
  end;
 
type
  TAutoAllocArrayDim4 = class(TObject) //tablica czterowymiarowa
                                       //four-dimensional array
    private
      FArr4: array of array of array of array of Variant;
      function  GetArr(aIndex1, aIndex2, aIndex3, aIndex4: integer): Variant;
      procedure SetArr(aIndex1, aIndex2, aIndex3, aIndex4: integer;
                         aValue: Variant);
      procedure ReDim (aIndex1, aIndex2, aIndex3, aIndex4: integer);
    public
      CannotAlloc: boolean; //jeśli true, alokacja się nie powiodła (zwykle
                            //przekroczono 2GB)
                            //
                            //if true, allocation failed (ussualy 2GB
                            //overallocated means over type capacity)
      procedure    Clear;
      property     Arr[aIndex1, aIndex2, aIndex3, aIndex4: integer]: Variant
                     read GetArr write SetArr; default;
            //ponieważ użyto default można się odwołać np. A[5, 6, 2, 12] := 1,
            //a nie A.Arr[5, 6, 2, 12] := 1
            //
            //because of use of the 'default' directive you can call eg.
            //A[5, 6, 2, 12] := 1, and you do not need A.Arr[5, 6, 2, 12] := 1
      constructor  Create;
      destructor   Destroy; override;
  end;
 
implementation





Funkcje tablicy jednowymiarowej / One-dimmensional array functions

{Funkcje tablicy jednowymiarowej / One-dimensional array functions}
 
procedure TAutoAllocArrayDim1.Clear;
begin
  SetLength(FArr1, 0);
end;
 
constructor TAutoAllocArrayDim1.Create;
begin
  inherited;
  SetLength(FArr1, 0);
end;
 
destructor TAutoAllocArrayDim1.Destroy;
begin
  Clear;
  inherited;
end;
 
procedure TAutoAllocArrayDim1.ReDim(aIndex: integer);
{
Procedura sprawdza, czy użyty indeks jest większy od największego użytego do tej
pory.
 
Jeżeli nie jest, nic nie robi w danym wymiarze tablicy.
 
Jeżeli jest, zwiększa rozmiar tablicy do użyty_index + 1 w danym wymiarze
tablicy.
 
Tu: w wymiarze pierwszym.
}
{
The routine tests if used input parameter index is greater than greatest till
particular moment.
 
If one isn't does nothing to array size.
 
If one is, the size of the array is incremented  used_index + 1 in a single
array dimension.
 
Here: in the first dimension.
}
begin
    try
      if Length(FArr1) < aIndex + 1 then
        SetLength(FArr1, aIndex + 1);
      CannotAlloc := false;
    except
      CannotAlloc := true;
    end;
end;
 
function TAutoAllocArrayDim1.GetArr(aIndex: integer): Variant;
begin
  ReDim(aIndex);
  Result := FArr1[aIndex];
end;
 
procedure TAutoAllocArrayDim1.SetArr(aIndex: integer; aValue: Variant);
begin
  ReDim(aIndex);
  FArr1[aIndex] := aValue;
end;






Funkcje tablicy dwuwymiarowej / Two-dimmensional array functions

{Funkcje tablicy dwuwymiarowej / Two-dimensional array functions}
 
procedure TAutoAllocArrayDim2.Clear;
var
  i: integer;
begin
  for i := 0 to Length(FArr2) - 1 do
    SetLength(FArr2[i], 0);
  SetLength(FArr2, 0);
end;
 
constructor TAutoAllocArrayDim2.Create;
begin
  inherited;
  SetLength(FArr2, 0);
end;
 
destructor TAutoAllocArrayDim2.Destroy;
begin
  Clear;
  inherited;
end;
 
procedure TAutoAllocArrayDim2.ReDim(aIndex1, aIndex2: integer);
{
Procedura sprawdza, czy użyty indeks jest większy od największego użytego do tej
pory.
 
Jeżeli nie jest, nic nie robi w danym wymiarze tablicy.
 
Jeżeli jest, zwiększa rozmiar tablicy do użyty_index + 1 w danym wymiarze
tablicy.
 
Tu: w wymiarze pierwszym, drugim.
 
Uwaga: Istotna jest kolejność tej operacji:
      najpierw pierwszy wymiar,
      potem drugi wymiar.
}
{
The routine tests if used input parameter index is greater than greatest till
particular moment.
 
If one isn't does nothing to array size.
 
If one is, the size of the array is incremented  used_index + 1 in a single
array dimension.
 
Here: in the first one and the second one.
 
Note: The order of successive operations is important:
      firstly first dimension,
      next second dimension.
}
begin
    try
      if Length(FArr2) < aIndex1 + 1 then
        SetLength(FArr2, aIndex1 + 1);
      if Length(FArr2[aIndex1]) < aIndex2 + 1 then
        SetLength(FArr2[aIndex1], aIndex2 + 1);
      CannotAlloc := false;
    except
      CannotAlloc := true;
    end;
end;
 
function TAutoAllocArrayDim2.GetArr(aIndex1, aIndex2: integer): Variant;
begin
  ReDim(aIndex1, aIndex2);
  Result := FArr2[aIndex1, aIndex2];
end;
 
procedure TAutoAllocArrayDim2.SetArr(aIndex1, aIndex2: integer; aValue: Variant)
  ;
begin
  ReDim(aIndex1, aIndex2);
  FArr2[aIndex1, aIndex2] := aValue;
end;





Funkcje tablicy trójwymiarowej / Three-dimmensional array functions

{Funkcje tablicy trójwymiarowej / Three-dimensional array functions}
 
procedure TAutoAllocArrayDim3.Clear;
var
  i, j: integer;
begin
  for i := 0 to Length(FArr3) - 1 do
  begin
    for j := 0 to Length(FArr3[i]) - 1 do
      SetLength(FArr3[i, j], 0);
    SetLength(FArr3[i], 0);
  end;
  SetLength(FArr3, 0);
end;
 
constructor TAutoAllocArrayDim3.Create;
begin
  inherited;
  SetLength(FArr3, 0);
end;
 
destructor TAutoAllocArrayDim3.Destroy;
begin
  Clear;
  inherited;
end;
 
procedure TAutoAllocArrayDim3.ReDim(aIndex1, aIndex2, aIndex3: integer);
{
Procedura sprawdza, czy użyty indeks jest większy od największego użytego do tej
pory.
 
Jeżeli nie jest, nic nie robi w danym wymiarze tablicy.
 
Jeżeli jest, zwiększa rozmiar tablicy do użyty_index + 1 w danym wymiarze
tablicy.
 
Tu: w wymiarze pierwszym, drugim, trzecim.
 
Uwaga:Istotna jest kolejność tej operacji:
      najpierw pierwszy wymiar,
      potem drugi wymiar,
      potem trzeci wymiar.
}
{
The routine tests if used input parameter index is greater than greatest till
particular moment.
 
If one isn't does nothing to array size.
 
If one is, the size of the array is incremented  used_index + 1 in a single
array dimension.
 
Here: in the first one, and the second one, and the third one
 
Note: The order of successive operations is important:
      firstly first dimension,
      secondly second dimension,
      finally third dimension.
}
begin
    try
      if Length(FArr3) < aIndex1 + 1 then
        SetLength(FArr3, aIndex1 + 1);
      if Length(FArr3[aIndex1]) < aIndex2 + 1 then
        SetLength(FArr3[aIndex1], aIndex2 + 1);
      if Length(FArr3[aIndex1, aIndex2]) < aIndex3 + 1 then
        SetLength(FArr3[aIndex1, aIndex2], aIndex3 + 1);
      CannotAlloc := false;
    except
      CannotAlloc := true;
    end;
end;
 
function TAutoAllocArrayDim3.GetArr(aIndex1, aIndex2, aIndex3: integer)
  : Variant;
begin
  ReDim(aIndex1, aIndex2, aIndex3);
  Result := FArr3[aIndex1, aIndex2, aIndex3];
end;
 
procedure TAutoAllocArrayDim3.SetArr(aIndex1, aIndex2, aIndex3: integer;
                                       aValue: Variant);
begin
  ReDim(aIndex1, aIndex2, aIndex3);
  FArr3[aIndex1, aIndex2, aIndex3] := aValue;
end;





Funkcje tablicy czterowymiarowej / Four-dimmensional array functions

{Funkcje tablicy czterowymiarowej / Four-dimensional array functions}
 
procedure TAutoAllocArrayDim4.Clear;
var
  i, j, k: integer;
begin
  for i := 0 to Length(FArr4) - 1 do
  begin
    for j := 0 to Length(FArr4[i]) - 1 do
    begin
      for k := 0 to Length(FArr4[i, j]) - 1 do
        SetLength(FArr4[i, j, k], 0);
      SetLength(FArr4[i, j], 0);
    end;
    SetLength(FArr4[i], 0);
  end;
  SetLength(FArr4, 0);
end;
 
constructor TAutoAllocArrayDim4.Create;
begin
  inherited;
  SetLength(FArr4, 0);
end;
 
destructor TAutoAllocArrayDim4.Destroy;
begin
  Clear;
  inherited;
end;
 
procedure TAutoAllocArrayDim4.ReDim(aIndex1, aIndex2, aIndex3, aIndex4: integer)
  ;
{
Procedura sprawdza, czy użyty indeks jest większy od największego użytego do tej
pory.
 
Jeżeli nie jest, nic nie robi w danym wymiarze tablicy.
 
Jeżeli jest, zwiększa rozmiar tablicy do użyty_index + 1 w danym wymiarze
tablicy.
 
Tu: w wymiarze pierwszym, drugim, trzecim, czwartym.
 
Uwaga: Istotna jest kolejność tej operacji:
      najpierw pierwszy wymiar,
      potem drugi wymiar,
      potem trzeci wymiar,
      potem czwarty wymiar.
}
{
The routine tests if used input parameter index is greater than greatest till
particular moment.
 
If one isn't does nothing to array size.
 
If one is, the size of the array is incremented  used_index + 1 in a single
array dimension.
 
Here: in the first one, and the second one, and the third one
 
Note: The order of successive operations is important:
      firstly first dimension,
      secondly second dimension,
      thirdly third dimension,
      finally fourth dimension.
}
begin
    try
      if Length(FArr4) < aIndex1 + 1 then
        SetLength(FArr4, aIndex1 + 1);
      if Length(FArr4[aIndex1]) < aIndex2 + 1 then
        SetLength(FArr4[aIndex1], aIndex2 + 1);
      if Length(FArr4[aIndex1, aIndex2]) < aIndex3 + 1 then
        SetLength(FArr4[aIndex1, aIndex2], aIndex3 + 1);
      if Length(FArr4[aIndex1, aIndex2, aIndex3]) < aIndex4 + 1 then
        SetLength(FArr4[aIndex1, aIndex2, aIndex3], aIndex4 + 1);
      CannotAlloc := false;
    except
      CannotAlloc := true;
    end;
end;
 
function TAutoAllocArrayDim4.GetArr(aIndex1, aIndex2, aIndex3, aIndex4: integer)
  : Variant;
begin
  ReDim(aIndex1, aIndex2, aIndex3, aIndex4);
  Result := FArr4[aIndex1, aIndex2, aIndex3, aIndex4];
end;
 
procedure TAutoAllocArrayDim4.SetArr(aIndex1, aIndex2, aIndex3,
                                       aIndex4: integer; aValue: Variant);
begin
  ReDim(aIndex1, aIndex2, aIndex3, aIndex4);
  FArr4[aIndex1, aIndex2, aIndex3, aIndex4] := aValue;
end;





Przykład użycia / Example of use

procedure TFormMain.Button1Click(Sender: TObject);
var
  a: TAutoAllocArrayDim4;
  b: TAutoAllocArrayDim2;
  s: string;
  i: integer;
begin
  try
    a := TAutoAllocArrayDim4.Create;
    b := TAutoAllocArrayDim2.Create;
    a[2, 1, 3, 1] := 'Artur';
    s := a[2, 1, 3, 1]; //s = 'Artur'
    s := a[4, 2, 0, 3]; //s = ''
    b[10, 7] := 33;
    i := b[10, 7]; // 33
    i := b[21, 8]; // 0
    MessageDlg('Operacja się powiodła / Operation successful',
      mtInformation, [mbOK], 0);
  except
    MessageDlg('Operacja się nie powiodła / Operation error', mtError, [mbOK],
      0);
  end;
end;


Wersja projektu gotowa do uruchomienia (pełna) do pobrania / Version of project ready to run (full) to download


Uwagi / Notes


Po polsku

(Angielski poniżej / English below)

01.        Zrobiłem projekt z jedna forma do testów i jednym modułem zawierającym kod proponowanego rozwiązania.
02.        Wersję tą można rozwijać we własnym zakresie w zależności od zastosowania i możliwości sprzedaży.
03.        Prototyp jest napisany w Delphi.
04.        Projekt w formie .zip jest załącznikiem do artykułu na serwerze 4programmers.net.
05.        Program wymaga Turbo Delphi Explorer (2006) lub nowszego i bardziej rozbudowanego środowiska Delphi.
06.        Program powstał w darmowym, komercyjnym, zarejestrowanym środowisku programistycznym Turbo Delphi Explorer (2006) na legalnym systemie Windows 7 Profeessional.
07.        Program jest przeznaczony dla Windows XP/7 i na tych systemach działa.
08.        Nie oczekuję żadnych opłat za udostępniony prototyp.
09.        Nie patentowałem nigdy i nie zastrzegałem kodu źródłowego przed użyciem.
10.        Kod był wcześniej publikowany na stronie www.protasewicz.pl, która już nie istnieje.
11.        Kod zawiera komentarze polsko-angielskie, jest przejrzysty, prosty, a użyte w kodzie nazewnictwo jest angielskie. Powinien być zrozumiały nawet dla średnio-zaawansowanego programisty, nawet niekoniecznie Delphi.
12.        Prototyp jest programem działającym lecz wymaga dodania własnego kodu do zaawansowanych testów.
13.        Będzie mi miło, jeśli komuś uda się zarobić i mnie o tym poinformuje, ale nie jest to mój wymóg.
14.        Uzupełnieniem kodu pozostaje powyższy artykuł.

English

01.        I made a project with single form for tests and single module with code of proposed solution.
02.        Version that can be developed in-house, depending on the application and sales opportunities.
03.        The prototype is written in Delphi.
04.        The project as a. zip is attached to an article on server 4programmers.net.
05.        The program requires Turbo Delphi Explorer (2006) or higher and more extended.
06.        The program is free, commercial, registered as a development environment Turbo Delphi Explorer (2006) on the legal system, Windows 7 Profeessional.
07.        The program is designed for Windows XP / 7 and those systems works.
08.        I do not expect any charges for the provision of a prototype.
09.        Did not patent ever and has not prohibited the source code before use.
10.        Code was previously published on the www.protasewicz.pl, which no longer exists.
11.        Code contains Polish-English comments, it is clear, simple, and used in code naming is English. It should be understandable even for medium-advanced programmer, even not necessarily Delphi.
12.        The prototype is a working program, but it needs to be extended with additional code for advaced test.
13.        I would be glad if someone manages to earn and tell me about it, but that is not my requirement.
14.        Complementing the code remains above article.


SelfAllocArr.zip (233,58 KB)

9 komentarzy

Artur Protasewicz 2014-01-31 20:30

Na razie muszę się wyleczyć z csharp.

pixelplus 2014-01-31 19:34

artykuł dobry, wielki + za chęci oraz rezultat. Tylko dlaczego Debian + Chromium AOKP wywala artykuł przedzielony jakimś syfem chińskim?
na win7 + Chrome jest wszystko ok.

Artur Protasewicz 2011-07-10 07:52

Tytułem uzupełnienia w odpowiedzi na komentarz łapczaka...
Jeżeli napiszesz for i := 0 to 100000 do a[i] := 5, to alokacja ma miejsce w każdej iteracji.
Jeżeli napiszesz for i := 100000 to 0 do a[i] := 5, to alokacja ma miejsce tylko jeden raz.

łapczak 2011-07-01 09:52

Bardzo to wygodne, ale STRASZNIE WOLNE ... alokacja pamięci dla tablicy jest zapisywana przy dodaniu każdego nowego rekordu. Zapisanie 10 000+ rekordów już mija się z celem.

Artur Protasewicz 2011-02-16 14:48

Dziękuję madmike. Twoja wersja jest lepsza.

madmike 2011-02-16 13:32

Świetny artykuł

Dodałem tabelkę z typami konwersji - autor zdecyduje czy pozostawić - które rozwiązanie jest bardziej czytelne: spis czy tabela

Artur Protasewicz 2011-02-14 06:11

W metodach Clear poprawiłem na Length(Arr) - 1. 10 miesięcy tu jest ten artykuł i wydaje mi się, że był w miarę popularny, a nikt tego nie zauważył? Chyba, że wszyscy, którzy korzystali poprawili sobie sami.
Od niedawna mam stronę:
http://protasewicz.pl
na której akurat ten kod chciałem zamieścić i znalazłem ten błąd. Na stronie jest również trochę matematyczne rozwinięcie na wypadek, gdybyś akurat potrzebował tablicy np. 10-wymiarowej, chociaż regułę budowania kolejnych wymiarów można zaobserwować i tutaj i sądzę, że większość nie będzie miała problemu, ale może ktoś jednak będzie tego potrzebował.
Ostatnio rzadko tu bywam, więc pozdrawiam wszystkich.

Artur Protasewicz 2010-04-04 10:39

MSM, wielkie, wielkie dzięki za uporządkowanie tego tematu i zmobilizowanie mnie do roboty. Praca zespołowa się opłaca.

msm 2010-04-03 10:07

Ciekawy pomysł z tą biblioteką, ale jak z wydajnością? I straszny bałagan w tym kodzie, dodałbyś chociaż jakieś komentarze, bo ciężko coś zrozumieć :/