Pole s proměnnou délkou - Variable-length array

V počítačovém programování je pole s proměnnou délkou ( VLA ), nazývané také proměnná velikost nebo velikost za běhu , datová struktura pole, jejíž délka je určena v době běhu (namísto v době kompilace). V C má VLA variabilně upravený typ, který závisí na hodnotě (viz Závislý typ ).

Hlavním účelem VLA je zjednodušit programování numerických algoritmů.

Mezi programovací jazyky, které podporují VLA, patří Ada , Algol 68 (pro neflexibilní řádky), APL , C99 (přestože jsou následně zařazeny v C11 do podmíněných funkcí, jejichž implementace nejsou vyžadovány k podpoře; na některých platformách by mohly být implementovány dříve s alloca()nebo podobné funkce) a C# (jako pole přidělená zásobníkům v nebezpečném režimu), COBOL , Fortran 90 , J a Object Pascal (jazyk používaný v Borland Delphi a Lazarus , který používá FPC).

Paměť

Přidělení

  • The GNU C přiděluje paměť pro Vlas s automatickou dobu skladování v zásobníku . Toto je rychlejší a přímočařejší možnost ve srovnání s alokací haldy a používá ji většina překladačů.
  • VLA lze také přidělit na haldě a interně k nim přistupovat pomocí ukazatele na tento blok.

Implementace

C99

Následující funkce C99 přiděluje pole proměnné délky zadané velikosti, vyplní ho hodnotami s plovoucí desetinnou čárkou a poté předá jiné funkci ke zpracování. Protože je pole deklarováno jako automatická proměnná, jeho životnost končí read_and_process()návratem.

float read_and_process(int n)
{
    float vals[n];

    for (int i = 0; i < n; ++i)
        vals[i] = read_val();

    return process(n, vals);
}

V C99 musí parametr délky přijít před parametr pole proměnné délky ve volání funkcí. V C11 __STDC_NO_VLA__je definováno makro, pokud není podporován VLA. GCC měl VLA jako rozšíření před C99, které také zasahuje do jeho dialektu C ++.

Linus Torvalds v minulosti vyjádřil svou nelibost nad používáním VLA pro pole s předem určenými malými velikostmi, protože generuje kód sestavy nižší kvality. S jádrem Linux 4.20 je jádro Linuxu prakticky bez VLA.

Ačkoli C11 výslovně neuvádí omezení velikosti pro VLA, některé hodnoty se domnívají, že by měla mít stejnou maximální velikost jako všechny ostatní objekty, tj. SIZE_MAX bajtů. Toto čtení by však mělo být chápáno v širším kontextu limitů prostředí a platforem, jako je typická velikost stránky strážce zásobníku 4 KiB, která je o mnoho řádů menší než SIZE_MAX.

Je možné mít VLA s dynamickým úložištěm pomocí ukazatele na pole.

float read_and_process(int n)
{
    float (*vals)[n] = malloc(sizeof(int[n]));

    for (int i = 0; i < n; ++i)
        (*vals)[i] = read_val();

    float ret = process(n, *vals);
    
    free(vals);
    
    return ret;
}

Ada

Následuje stejný příklad v Ada . Pole Ada s sebou nesou své hranice, takže není nutné předávat délku funkci Process.

type Vals_Type is array (Positive range <>) of Float;

function Read_And_Process (N : Integer) return Float is
   Vals : Vals_Type (1 .. N);
begin
   for I in 1 .. N loop
      Vals (I) := Read_Val;
   end loop;
   return Process (Vals);
end Read_And_Process;

Fortran 90

Ekvivalentní funkce Fortran 90 je

function read_and_process(n) result(o)
    integer,intent(in)::n
    real::o

    real,dimension(n)::vals
    integer::i

    do i = 1,n
       vals(i) = read_val()
    end do
    o = process(vals)
end function read_and_process

při využití funkce Fortran 90 kontroly rozhraní procedur v době kompilace; na druhou stranu, pokud funkce používají rozhraní volání před Fortran 90, musí být (externí) funkce nejprve deklarovány a délka pole musí být explicitně předána jako argument (jako v C):

function read_and_process(n) result(o)
    integer,intent(in)::n
    real::o

    real,dimension(n)::vals
    real::read_val, process
    integer::i

    do i = 1,n
       vals(i) = read_val()
    end do
    o = process(vals,n)
end function read_and_process

Cobol

Následující fragment COBOL deklaruje pole záznamů DEPT-PERSONs proměnnou délkou, jejichž délka (počet členů) je určena hodnotou PEOPLE-CNT:

DATA DIVISION.
WORKING-STORAGE SECTION.
01  DEPT-PEOPLE.
    05  PEOPLE-CNT          PIC S9(4) BINARY.
    05  DEPT-PERSON         OCCURS 0 TO 20 TIMES DEPENDING ON PEOPLE-CNT.
        10  PERSON-NAME     PIC X(20).
        10  PERSON-WAGE     PIC S9(7)V99 PACKED-DECIMAL.

COBOL VLA, na rozdíl od jiných jazyků je uvedeno zde, je v bezpečí, protože COBOL vyžaduje jednu určit velikost maximální pole - v tomto případě DEPT-PERSONnemůže mít více než 20 položek, bez ohledu na hodnotu PEOPLE-CNT.

C#

Následující fragment C# deklaruje pole s proměnnou délkou celých čísel. Před verzí C# 7.2 je vyžadován ukazatel na pole, který vyžaduje kontext „nebezpečný“. Klíčové slovo „nebezpečné“ vyžaduje, aby bylo sestavení obsahující tento kód označeno jako nebezpečné.

unsafe void DeclareStackBasedArrayUnsafe(int size)
{
    int *pArray = stackalloc int[size];
    pArray[0] = 123;
}

C# verze 7.2 a novější umožňují přidělení pole bez klíčového slova „nebezpečné“ pomocí funkce Span.

void DeclareStackBasedArraySafe(int size)
{
    Span<int> stackArray = stackalloc int[size];
    stackArray[0] = 123;
}

Objekt Pascal

V tomto jazyce se tomu říká dynamické pole. Deklarace takové proměnné je podobná deklaraci statického pole, ale bez určení její velikosti. Velikost pole je uvedena v době jeho použití.

program CreateDynamicArrayOfNumbers(Size: Integer);
var
  NumberArray: array of LongWord;
begin
  SetLength(NumberArray, Size);
  NumberArray[0] := 2020;
end.

Odebrání obsahu dynamického pole se provádí přiřazením velikosti nula.

...
SetLength(NumberArray, 0);
...

Reference