Variabel längd array

Inom datorprogrammering är en variabel längd array ( VLA ), även kallad variabel storlek eller runtime-sized , en array-datastruktur vars längd bestäms vid körning (istället för vid kompilering). I C sägs VLA ha en variabelt modifierad typ som beror på ett värde (se Beroende typ ) .

Huvudsyftet med VLA:er är att förenkla programmering av numeriska algoritmer.

Programmeringsspråk som stöder VLA:er inkluderar Ada , Algol 68 (för icke-flexibla rader), APL , C99 (även om de senare har förvisats i C11 till en villkorad funktion, som implementeringar inte krävs för att stödja; på vissa plattformar kunde VLA implementeras tidigare med alloca () eller liknande funktioner) och C# (som stackallokerade arrayer i osäkert läge), COBOL , Fortran 90 , J och Object Pascal (språket som används i Borland Delphi och Lazarus , som använder FPC).

Växbara arrayer (även kallade dynamiska arrayer ) är i allmänhet mer användbara än VLA:er eftersom dynamiska arrayer kan göra allt som VLA:er kan göra, och även stöder att växa arrayen under körning. Av denna anledning stöder många programmeringsspråk (JavaScript, Java, Python, R, etc.) endast odlingsbara arrayer. Även i programmeringsspråk som stöder arrayer med variabel längd, rekommenderas det ofta att undvika att använda (stackbaserade) arrayer med variabel längd, och istället använda (högbaserade) dynamiska arrayer.

Minne

Tilldelning

  • GNU C-kompilatorn allokerar minne för VLA:er med automatisk lagringstid stacken . Detta är det snabbare och enklare alternativet jämfört med heap-allokering och används av de flesta kompilatorer.
  • VLA:er kan också allokeras på heapen och nås internt med hjälp av en pekare till detta block.

Genomförande

C99

Följande C99 -funktion allokerar en array med variabel längd av en specificerad storlek, fyller den med flyttalsvärden och skickar den sedan till en annan funktion för bearbetning. Eftersom arrayen deklareras som en automatisk variabel, slutar dess livslängd när read_and_process() returnerar.

  

     

        0    
          

      
 float  read_and_process  (  int  n  )  {  float  vals  [  n  ];  för  (  int  i  =  ;  i  <  n  ;  ++  i  )  vals  [  i  ]  =  read_val  ();  returprocess  (  n  ,  vals  )  ;  } 

I C99 måste längdparametern komma före arrayparametern med variabel längd i funktionsanrop. I C11 definieras ett __STDC_NO_VLA__ makro om VLA inte stöds. C23-standarden gör VLA-typer obligatoriska igen. Endast skapande av VLA-objekt med automatisk lagringstid är valfritt. GCC hade VLA som en förlängning före C99, en som även sträcker sig in i sin C++-dialekt.

Linus Torvalds har tidigare uttryckt sitt missnöje över VLA-användning för arrayer med förutbestämda små storlekar eftersom det genererar sammansättningskod av lägre kvalitet. Med Linux 4.20-kärnan Linux-kärnan faktiskt VLA-fri.

Även om C11 inte uttryckligen anger en storleksgräns för VLA:er, anser vissa att den bör ha samma maximala storlek som alla andra objekt, dvs SIZE_MAX byte. Detta bör dock förstås i det bredare sammanhanget av miljö- och plattformsbegränsningar, såsom den typiska stack-guard-sidstorleken på 4 KiB, vilket är många storleksordningar mindre än SIZE_MAX.

Det är möjligt att ha VLA-liknande syntax med dynamisk lagring genom att använda en pekare till en array.

  

       

        0    
          

        
    
    
    
     
 float  read_and_process  (  int  n  )  {  float  (  *  vals  )[  n  ]  =  malloc  (  sizeof  (  float  [  n  ]) );  för  (  int  i  =  ;  i  <  n  ;  ++  i  )  (  *  vals  )[  i  ]  =  read_val  ();  float  ret  =  process  (  n  ,  *  vals  );  gratis  (  vals  );  return  ret  ;  } 

Ada

Följande är samma exempel i Ada . Ada-matriser bär sina gränser med sig, så det finns ingen anledning att överföra längden till Process-funktionen.

        

      
        

         
         
    
     
  typ  Vals_Type  är  array  (  positivt  intervall  <>)  av  Float  ;  funktion  Read_And_Process  (  N  :  Heltal  )  return  Float  är  Vals  :  Vals_Type  (  1..N  )  ;  _  börja  för  I  i  1  ..  N  loop  Vals  (  I  )  :=  Read_Val  ;  ändslinga  ;  _  returprocess  (  Vals  )  ;  avsluta  Read_And_Process  ; 

Fortran 90

Motsvarande Fortran 90 -funktion är

 
    
    

    
    

      
         
    
      
 funktion  read_and_process  (  n  )  resultat  (  o  )  heltal  ,  intent  (  in  )  ::  n  real  ::  o  real  ,  dimension  (  n  )  ::  vals  heltal  ::  i  do  i  =  1  ,  n  vals  (  i  )  =  read_val  ()  end do  o  =  process  (  vals  )  slutfunktionen  read_and_process 

när man använder Fortran 90-funktionen för att kontrollera procedurgränssnitt vid kompilering; å andra sidan, om funktionerna använder pre-Fortran 90-anropsgränssnitt, måste de (externa) funktionerna först deklareras, och arraylängden måste uttryckligen skickas som ett argument (som i C):

 
    
    

    
     
    

      
         
    
      
 funktion  read_and_process  (  n  )  resultat  (  o  )  heltal  ,  intent  (  in  )  ::  n  real  ::  o  real  ,  dimension  (  n  )  ::  vals  real  ::  read_val  ,  process  heltal  ::  i  do  i  =  1  ,  n  vals  (  i  )  =  read_val  ()  end do  o  =  process  (  vals  ,  n  )  end function  read_and_process 

Cobol

Följande COBOL- fragment deklarerar en array av poster med variabel längd DEPT-PERSON med en längd (antal medlemmar) som anges av värdet PEOPLE-CNT :

 
 

               
              0     
             
               DATA  DIVISION  .  ARBETS-  LAGRING  .  01  DEPT-PERSONER  .  05  PEOPLE-CNT  PIC S9(4)  BINÄRT  .  05  AVDELNINGSPERSON  FÖREKOMMER  TILL  20  GANGER  BEROENDE  PERSONER-CNT  .  10  PERSON-NAMN  BILD X(20)  .  10  PERSONSLÖN  PIC S9(7)V99  PACKAD-DECIMAL  . 

COBOL VLA, till skillnad från det för andra språk som nämns här, är säkert eftersom COBOL kräver att man specificerar den maximala arraystorleken – i det här exemplet kan DEPT -PERSON inte ha mer än 20 objekt, oavsett värdet på PEOPLE-CNT .

C#

Följande C# -fragment deklarerar en array med variabel längd av heltal. Före C# version 7.2 krävs en pekare till arrayen, vilket kräver en "osäker" kontext. Nyckelordet "osäkert" kräver att en sammansättning som innehåller denna kod markeras som osäker.

   

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

C# version 7.2 och senare tillåter att arrayen allokeras utan nyckelordet "osäkra" genom användning av Span-funktionen.

  

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

Objekt Pascal

Objekt Pascal dynamiska arrayer allokeras på heapen.

På det här språket kallas det en dynamisk array. Deklarationen av en sådan variabel liknar deklarationen av en statisk array, men utan att specificera dess storlek. Storleken på arrayen anges vid tidpunkten för dess användning.

  

     

   
  0  
 programmet  CreateDynamicArrayOfNumbers  (  Storlek  :  Heltal  )  ;  var  NumberArray  :  array  av  LongWord  ;  begin  SetLength  (  NumberArray  ,  Size  )  ;  NumberArray  [  ]  :=  2020  ;  slut  . 

Att ta bort innehållet i en dynamisk array görs genom att tilldela den storleken noll.


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