Matrice de lungime variabilă

În programare , o matrice de lungime variabilă ( VLA, matrice de dimensiune variabilă, matrice de dimensiunea de rulare ) este o matrice a cărei lungime este determinată în timpul rulării (și nu în timpul compilării) [1] . În C, o matrice de lungime variabilă are un tip gestionat de variabile ( ing. tipul modificat variabil ), care depinde de o anumită valoare (vezi Tip dependent ).   

Scopul principal al tablourilor de lungime variabilă este de a simplifica programarea algoritmilor numerici.

Limbaje de programare care acceptă matrice cu lungime variabilă: Ada , Algol 68 (fără posibilitatea de a modifica lungimea șirurilor în matrice bidimensionale etc.), APL , C99 (deși mai târziu matricea cu lungime variabilă a devenit o caracteristică opțională în C11 , al cărui suport nu este necesar [2] [3] ; pe unele platforme, este posibil să fi fost implementat anterior cu o funcție alloca()sau similar) și C# (matrice alocate pe stivă - această caracteristică este disponibilă numai în modul nesigur), COBOL , Fortran 90 , J și Object Pascal (limbajul folosit de către mediiBorland Delphi și Lazarus compilează cu Free Pascal Compiler).

Memorie

Alocarea memoriei

Implementare

C99

Următoarea funcție C99 alocă o matrice de lungime variabilă de o dimensiune dată, o umple cu valori în virgulă mobilă și apoi o transmite unei alte funcții pentru procesare. Deoarece matricea este declarată ca o variabilă automată, durata sa de viață se termină când read_and_process().

float read_and_process ( int n ) { float vals [ n ]; pentru ( int i = 0 ; i < n ; ++ i ) vals [ i ] = read_val (); procesul de returnare ( n , vals ); }

În C99, parametrul de lungime trebuie să precedă parametrul de matrice de lungime variabilă în apelurile de funcție [1] . C11 definește o macrocomandă __STDC_NO_VLA__dacă matricele de lungime variabilă nu sunt suportate [5] . GCC avea matrice de lungime variabilă ca extensie înainte de C99, care se extinde și la dialectul său C++.

Linus Torvalds și-a exprimat nemulțumirea în trecut cu privire la utilizarea matricelor mici de lungime variabilă, deoarece acest lucru generează cod de asamblare de calitate inferioară [6] . Nucleul Linux 4.20 nu conține de fapt matrice de lungime variabilă [ 7] .

Deși C11 nu stabilește în mod explicit o limită de dimensiune pentru matrice de lungime variabilă, unele interpretări sugerează că acestea ar trebui să aibă aceeași dimensiune maximă ca toate celelalte obiecte, de exemplu. SIZE_MAXoctet [8] . Cu toate acestea, această interpretare trebuie înțeleasă în contextul mai larg al limitărilor de mediu și platformă, cum ar fi o dimensiune tipică a paginii cu protecție a stivei de 4 KiB, care este cu multe ordine de mărime mai mică decât SIZE_MAX.

Puteți utiliza o sintaxă asemănătoare matricei de lungime variabilă cu stocare dinamică folosind un pointer către o matrice.

float read_and_process ( int n ) { float ( * vals )[ n ] = malloc ( sizeof ( float [ n ])); pentru ( int i = 0 ; i < n ; ++ i ) ( * vals )[ i ] = read_val (); float ret = proces ( n , * vals ); liber ( vals ); return ret ; }

Ada

Mai jos este același exemplu în Ada . Matricele conțin lungimea lor împreună cu datele, deci nu este nevoie să treceți lungimea lor la funcția Process.

tipul Vals_Type este o matrice ( gamă pozitivă <>) de Float ; function Read_And_Process ( N : Integer ) return Float is Vals : Vals_Type ( 1 .. N ); începe pentru I în 1 .. N buclă Vals ( I ) := Read_Val ; buclă de capăt ; Procesul de returnare ( Vals ); sfârşit Read_And_Process ;

Fortran 90

Funcție echivalentă în limbajul Fortran 90 .

funcția read_and_process ( n ) rezultat ( o ) întreg , intent ( în ) :: n real :: o real , dimensiune ( n ) :: vals întreg :: i do i = 1 , n vals ( i ) = read_val () end do o = process ( vals ) end function read_and_process

Utilizează caracteristica Fortran 90 pentru a testa interfețele procedurilor în timpul compilării; pe de altă parte, dacă funcțiile folosesc interfața de apelare pre-Fortran 90, funcțiile (externe) trebuie declarate mai întâi, iar lungimea matricei trebuie transmisă explicit ca argument (ca în C):

funcția read_and_process ( n ) rezultat ( o ) întreg , intent ( în ) :: n real :: o real , dimensiune ( n ) :: vals real :: read_val , proces întreg :: i do i = 1 , n vals ( i ) = read_val ( ) end do o = process ( vals , n ) end function read_and_process

Cobol

Următorul fragment COBOL declară o matrice de înregistrare cu lungime variabilă de DEPT-PERSONlungime (număr de elemente) dată de PEOPLE-CNT:

DIVIZIUNEA DE DATE . SECTIUNEA DE LUCRU-DEPOZITARE . 01 DEPT-OAMENI . 05 OAMENI-CNT PIC S9(4) BINAR . 05 DEPT-PERSONA SE APARĂ DE LA 0 PÂNĂ LA 20 DE ORI ÎN FUNȚIE DE OAMENI -CNT . 10 NUME PERSOANĂ FOTO X(20) . 10 IMAGINĂ PERSOANĂ- SALARIE S9(7)V99 AMBALAT - DECIMALĂ .

Matricele cu lungime variabilă din COBOL , spre deosebire de celelalte limbi menționate aici, sunt sigure, deoarece COBOL vă solicită să specificați o dimensiune maximă a matricei - în acest exemplu, DEPT-PERSONnu poate conține mai mult de 20 de elemente, indiferent de valoarea lui PEOPLE-CNT.

C#

Următorul fragment C# declară o matrice cu lungime variabilă de numere întregi. Înainte de C# 7.2, era necesar un pointer către o matrice într-un context „nesigur”. Cuvântul cheie unsafenecesită ca ansamblul care conține acest cod să fie marcat ca nesigur.

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

C# versiunea 7.2 și ulterioară vă permite să alocați o matrice fără cuvântul cheie unsafefolosind funcția Span [9] .

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

ObjectPascal

În acest limbaj, o matrice de lungime variabilă este numită matrice dinamică. Declararea unei astfel de variabile este similară cu declararea unui tablou static, dar fără a specifica dimensiunea acesteia. Mărimea unei matrice este setată în momentul în care este utilizată.

program CreateDynamicArrayOfNumbers ( Dimensiune : Integer ) ; var NumberArray : matrice de LongWord ; începe SetLength ( NumberArray , Size ) ; NumberArray [ 0 ] := 2020 ; sfârşitul .

Ștergerea conținutului unui tablou dinamic se face dându-i o dimensiune de zero.

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

Link -uri

  1. 1 2 Variable Length Arrays . Arhivat din original pe 26 ianuarie 2018.
  2. Variable Length - Utilizarea GNU Compiler Collection (GCC) .
  3. Limbaje de programare ISO 9899:2011 - C 6.7.6.2 4.
  4. Code Gen Options - Compilatorul GNU Fortran .
  5. § 6.10.8.3 din standardul C11 (n1570.pdf)
  6. LKML: Linus Torvalds: Re: Îndepărtarea VLA (a fost Re: [Lustrul RFC 2/2 : utilizați VLA_SAFE)] . lkml.org .
  7. ↑ Kernel-ul Linux este acum fără VLA : o victorie pentru securitate, mai puține cheltuieli generale și mai bune pentru Clang - Phoronix  . www.phoronix.com .
  8. §6.5.3.4 și §7.20.3 din standardul C11 (n1570.pdf)
  9. operator stackalloc (referință C#) . Microsoft.