Matriz de longitud variable - Variable-length array

En programación de computadoras , una matriz de longitud variable ( VLA ), también llamada de tamaño variable o tamaño en tiempo de ejecución , es una estructura de datos de matriz cuya longitud se determina en tiempo de ejecución (en lugar de en tiempo de compilación). En C, se dice que el VLA tiene un tipo modificado de forma variable que depende de un valor (consulte Tipo dependiente ).

El objetivo principal de los VLA es simplificar la programación de algoritmos numéricos.

Los lenguajes de programación que admiten VLA incluyen Ada , Algol 68 (para filas no flexibles), APL , C99 (aunque posteriormente relegado en C11 a una característica condicional, que las implementaciones no deben admitir; en algunas plataformas, podría implementarse previamente con alloca()o funciones similares) y C # (como matrices asignadas en pila en modo inseguro), COBOL , Fortran 90 , J y Object Pascal (el lenguaje usado en Borland Delphi y Lazarus , que usa FPC).

Memoria

Asignación

  • El compilador GNU C asigna memoria para VLA con duración de almacenamiento automático en la pila . Esta es la opción más rápida y sencilla en comparación con la asignación de almacenamiento dinámico, y la utilizan la mayoría de los compiladores.
  • Los VLA también se pueden asignar en el montón y acceder internamente mediante un puntero a este bloque.

Implementación

C99

La siguiente función C99 asigna una matriz de longitud variable de un tamaño especificado, la llena con valores de punto flotante y luego la pasa a otra función para su procesamiento. Debido a que la matriz se declara como una variable automática, su vida útil finaliza cuando read_and_process()regresa.

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

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

    return process(n, vals);
}

En C99, el parámetro de longitud debe ir antes del parámetro de matriz de longitud variable en las llamadas a funciones. En C11, __STDC_NO_VLA__se define una macro si no se admite VLA. GCC tenía VLA como una extensión antes de C99, una que también se extiende a su dialecto C ++.

Linus Torvalds ha expresado su disgusto en el pasado por el uso de VLA para arreglos con tamaños pequeños predeterminados porque genera código de ensamblaje de menor calidad. Con el kernel de Linux 4.20, el kernel de Linux está efectivamente libre de VLA.

Aunque C11 no nombra explícitamente un límite de tamaño para los VLA, algunas lecturas creen que debería tener el mismo tamaño máximo que todos los demás objetos, es decir, SIZE_MAX bytes. Sin embargo, esta lectura debe entenderse en el contexto más amplio de los límites del entorno y la plataforma, como el tamaño de página típico de protección de pila de 4 KiB, que es muchos órdenes de magnitud más pequeño que SIZE_MAX.

Es posible tener VLA con almacenamiento dinámico con la ayuda de un puntero a una matriz.

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

El siguiente es el mismo ejemplo en Ada . Las matrices Ada llevan consigo sus límites, por lo que no es necesario pasar la longitud a la función 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

La función equivalente de Fortran 90 es

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

cuando se utiliza la función Fortran 90 de verificar las interfaces de los procedimientos en el momento de la compilación; por otro lado, si las funciones usan una interfaz de llamada anterior a Fortran 90, las funciones (externas) deben declararse primero y la longitud de la matriz debe pasarse explícitamente como un argumento (como en 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

El siguiente fragmento COBOL declara una matriz de registros de longitud variable que DEPT-PERSONtienen una longitud (número de miembros) especificada por el 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.

El COBOL VLA, a diferencia de la de otros idiomas menciona aquí, es seguro porque COBOL requiere uno para especificar el tamaño de la matriz máxima - en este ejemplo, DEPT-PERSONno puede tener más de 20 artículos, independientemente del valor de PEOPLE-CNT.

C#

El siguiente fragmento de C # declara una matriz de enteros de longitud variable. Antes de la versión 7.2 de C #, se requiere un puntero a la matriz, lo que requiere un contexto "inseguro". La palabra clave "inseguro" requiere que un ensamblado que contenga este código se marque como inseguro.

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

La versión 7.2 de C # y posteriores permiten que la matriz se asigne sin la palabra clave "inseguro", mediante el uso de la función Span.

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

Objeto Pascal

En este idioma, se llama matriz dinámica. La declaración de dicha variable es similar a la declaración de una matriz estática, pero sin especificar su tamaño. El tamaño de la matriz se da en el momento de su uso.

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

La eliminación del contenido de una matriz dinámica se realiza asignándole un tamaño de cero.

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

Referencias