Matriz de comprimento variável - Variable-length array

Na programação de computadores , um array de comprimento variável ( VLA ), também chamado de tamanho variável ou tamanho do tempo de execução , é uma estrutura de dados de array cujo comprimento é determinado em tempo de execução (em vez de no tempo de compilação). Em C, diz-se que o VLA tem um tipo de modificação variável que depende de um valor (consulte Tipo dependente ).

O principal objetivo dos VLAs é simplificar a programação de algoritmos numéricos.

As linguagens de programação que suportam VLAs incluem Ada , Algol 68 (para linhas não flexíveis), APL , C99 (embora posteriormente relegado em C11 a um recurso condicional, que as implementações não são obrigadas a suportar; em algumas plataformas, poderia ser implementado anteriormente com alloca()ou funções semelhantes) e C # (como arrays alocados em pilha de modo inseguro), COBOL , Fortran 90 , J e Object Pascal (a linguagem usada em Borland Delphi e Lazarus , que usa FPC).

Memória

Alocação

  • O GNU C Compiler aloca memória para VLAs com duração de armazenamento automática na pilha . Esta é a opção mais rápida e direta em comparação com a alocação de heap e é usada pela maioria dos compiladores.
  • Os VLAs também podem ser alocados no heap e acessados ​​internamente usando um ponteiro para este bloco.

Implementação

C99

A função C99 a seguir aloca uma matriz de comprimento variável de um tamanho especificado, preenche-a com valores de ponto flutuante e, a seguir, a passa para outra função para processamento. Como a matriz é declarada como uma variável automática, seu tempo de vida termina quando read_and_process()retorna.

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

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

    return process(n, vals);
}

Em C99, o parâmetro de comprimento deve vir antes do parâmetro de matriz de comprimento variável em chamadas de função. No C11, uma __STDC_NO_VLA__macro é definida se o VLA não for compatível. O GCC tinha o VLA como uma extensão antes do C99, que também se estende ao dialeto C ++.

Linus Torvalds expressou seu descontentamento no passado com o uso de VLA para matrizes com tamanhos pequenos predeterminados, porque gera código de montagem de qualidade inferior. Com o kernel Linux 4.20, o kernel Linux é efetivamente livre de VLA.

Embora C11 não nomeie explicitamente um limite de tamanho para VLAs, algumas leituras acreditam que ele deve ter o mesmo tamanho máximo que todos os outros objetos, ou seja, SIZE_MAX bytes. No entanto, essa leitura deve ser entendida no contexto mais amplo de limites de ambiente e plataforma, como o tamanho de página de proteção de pilha típico de 4 KiB, que é muitas ordens de magnitude menor que SIZE_MAX.

É possível ter VLAs com armazenamento dinâmico com a ajuda de um ponteiro para um array.

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

O seguinte é o mesmo exemplo em Ada . Os arrays Ada carregam seus limites com eles, portanto, não há necessidade de passar o comprimento para a função 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

A função Fortran 90 equivalente é

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

ao utilizar o recurso Fortran 90 de verificação de interfaces de procedimento em tempo de compilação; por outro lado, se as funções usam interface de chamada pré-Fortran 90, as funções (externas) devem primeiro ser declaradas e o comprimento da matriz deve ser explicitamente passado como um argumento (como em 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

O seguinte fragmento COBOL declara uma matriz de registros de comprimento variável DEPT-PERSONcom um comprimento (número de membros) especificado pelo valor de 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.

O COBOL VLA, ao contrário de outras linguagens mencionadas aqui, é seguro porque o COBOL requer que seja especificado o tamanho máximo do array - neste exemplo, DEPT-PERSONnão pode ter mais de 20 itens, independentemente do valor de PEOPLE-CNT.

C #

O fragmento C # a seguir declara uma matriz de números inteiros de comprimento variável. Antes do C # versão 7.2, um ponteiro para a matriz é necessário, exigindo um contexto "inseguro". A palavra-chave "inseguro" requer que um assembly contendo esse código seja marcado como inseguro.

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

C # versão 7.2 e posterior permitem que a matriz seja alocada sem a palavra-chave "insegura", por meio do uso do recurso Span.

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

Object Pascal

Nessa linguagem, é chamado de array dinâmico. A declaração de tal variável é semelhante à declaração de um array estático, mas sem especificar seu tamanho. O tamanho do array é dado no momento de seu uso.

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

A remoção do conteúdo de uma matriz dinâmica é feita atribuindo-lhe um tamanho zero.

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

Referências