En programación informática , una matriz de longitud variable ( VLA ), también llamada de tamaño variable o de 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 . [1] En el lenguaje C , se dice que la VLA tiene un tipo de datos modificado de forma variable que depende de un valor (ver Tipo dependiente ).
El propósito 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 están obligadas a admitir; [2] [3] en algunas plataformas, los VLA se podían implementar anteriormente con alloca()
o funciones similares) y C# (como matrices asignadas a la pila en modo inseguro ), COBOL , Fortran 90, J y Object Pascal (el lenguaje utilizado en Delphi y Lazarus , que utiliza FPC).
Las matrices ampliables (también llamadas matrices dinámicas ) son generalmente más útiles que las matrices de longitud variable porque las matrices dinámicas pueden hacer todo lo que las matrices de longitud variable pueden hacer y también admiten el crecimiento de la matriz en tiempo de ejecución. Por esta razón, muchos lenguajes de programación ( JavaScript , Java , Python , R , etc.) solo admiten matrices ampliables. Incluso en lenguajes que admiten matrices de longitud variable, a menudo se recomienda evitar el uso de matrices de longitud variable (basadas en pila) y, en su lugar, utilizar matrices dinámicas ( basadas en montón ). [4]
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 duración finaliza cuando read_and_process()
retorna.
flotante leer_y_procesar ( int n ) { flotante vals [ n ]; para ( int i = 0 ; i < n ; ++ i ) vals [ i ] = read_val (); proceso de retorno ( n , vals ); }
En C99, el parámetro de longitud debe ir antes del parámetro de matriz de longitud variable en las llamadas de función. [1] En C11, __STDC_NO_VLA__
se define una macro si no se admite VLA. [6] El estándar C23 vuelve a hacer obligatorios los tipos VLA. Solo la creación de objetos VLA con duración de almacenamiento automática es opcional. [7] 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 en el pasado su descontento con el uso de VLA para matrices con tamaños pequeños predeterminados porque genera código ensamblador de menor calidad. [8] Con el kernel Linux 4.20, el kernel Linux está efectivamente libre de VLA. [9]
Aunque C11 no nombra explícitamente un límite de tamaño para los VLA, algunos creen que debería tener el mismo tamaño máximo que todos los demás objetos, es decir, SIZE_MAX bytes. [10] Sin embargo, esto debería entenderse en el contexto más amplio de los límites del entorno y la plataforma, como el tamaño de página de protección de pila típico de 4 KiB, que es muchos órdenes de magnitud más pequeño que SIZE_MAX.
Es posible tener un objeto VLA con almacenamiento dinámico utilizando un puntero a una matriz.
flotante leer_y_procesar ( int n ) { flotante ( * vals )[ n ] = malloc ( sizeof ( float [ n ])); para ( int i = 0 ; i < n ; ++ i ) ( * vals )[ i ] = read_val (); float ret = proceso ( n , * vals ); libre ( vals ); devolver ret ; }
El siguiente es el mismo ejemplo en Ada . Las matrices de Ada llevan consigo sus límites, por lo que no es necesario pasar la longitud a la función Process.
tipo Vals_Type es una matriz ( rango positivo <>) de flotante ; función Read_And_Process ( N : Integer ) retorna Float es Vals : Vals_Type ( 1..N ) ; comienza para I en 1..N bucle Vals ( I ) : = Read_Val ; fin del bucle ; retorna Proceso ( Vals ) ; fin Read_And_Process ;
La función equivalente de Fortran 90 es
función leer_y_procesar ( n ) resultado ( o ) entero , intención ( en ) :: n real :: o real , dimensión ( n ) :: vals entero :: i hacer i = 1 , n vals ( i ) = leer_val () fin hacer o = proceso ( vals ) fin función leer_y_procesar
al utilizar la característica Fortran 90 de verificar interfaces de procedimientos en tiempo de 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 argumento (como en C):
función leer_y_procesar ( n ) resultado ( o ) entero , intención ( en ) :: n real :: o real , dimensión ( n ) :: vals real :: read_val , proceso entero :: i hacer i = 1 , n vals ( i ) = leer_val () fin hacer o = proceso ( vals , n ) fin función leer_y_procesar
El siguiente fragmento de COBOL declara una matriz de registros de longitud variable DEPT-PERSON
que tiene una longitud (número de miembros) especificada por el valor de PEOPLE-CNT
:
DIVISIÓN DE DATOS . SECCIÓN DE TRABAJO-ALMACENAMIENTO . 01 DEPT-PERSONAS . 05 PERSONAS-CNT PIC S9(4) BINARIO . 05 DEPT-PERSONA OCURRE DE 0 A 20 VECES DEPENDIENDO DE PERSONAS-CNT . 10 PERSONA-NOMBRE PIC X(20) . 10 PERSONA-SALARIO PIC S9(7)V99 PAQUETE-DECIMAL .
A diferencia de otros lenguajes mencionados aquí, el VLA de COBOLDEPT-PERSON
es seguro porque COBOL requiere especificar el tamaño máximo de la matriz. En este ejemplo, no puede tener más de 20 elementos, independientemente del valor de PEOPLE-CNT
.
El siguiente fragmento de C# declara una matriz de longitud variable de números enteros. Antes de la versión 7.2 de C#, se requería un puntero a la matriz, lo que requería un contexto "inseguro". La palabra clave "inseguro" requiere que un ensamblaje que contenga este código se marque como inseguro.
void inseguro DeclareStackBasedArrayUnsafe ( int tamaño ) { int * pArray = stackalloc int [ tamaño ]; pArray [ 0 ] = 123 ; }
La versión 7.2 de C# y posteriores permiten que la matriz se asigne sin la palabra clave "unsafe", mediante el uso de la función Span. [11]
void DeclareStackBasedArraySafe ( int tamaño ) { Span < int > stackArray = stackalloc int [ tamaño ]; stackArray [ 0 ] = 123 ; }
Las matrices dinámicas de Object Pascal se asignan en el montón. [12]
En este lenguaje, se denomina matriz dinámica. La declaración de una variable de este tipo es similar a la declaración de una matriz estática, pero sin especificar su tamaño. El tamaño de la matriz se indica en el momento de su uso.
programa CreateDynamicArrayOfNumbers ( Tamaño : Entero ) ; var NumberArray : matriz de LongWord ; comienzo SetLength ( NumberArray , Tamaño ) ; NumberArray [ 0 ] := 2020 ; fin .
La eliminación del contenido de una matriz dinámica se realiza asignándole un tamaño de cero.
... EstablecerLongitud ( NumberArray , 0 ) ; ...