可変長配列

出典: フリー百科事典『ウィキペディア(Wikipedia)』
ナビゲーションに移動 検索に移動

プログラミングにおいて、可変長配列(かへんちょうはいれつ、英語: variable-length array: VLA)とは、コンパイル時ではなく実行時に長さが決定される自動記憶期間英語版配列データ構造である[1]

VLAに対応しているプログラミング言語には、AdaALGOL 68(行は固定)、APLC99(ただしC11ではサポート必須ではなくオプションに格下げとなった[2][3]。またいくつかのプラットフォームにおいて、C99より前のバージョンではalloca()あるいは類似の関数で実装されることがあった)、C#(unsafeモードのスタック割り当て配列として)、COBOLFortran 90J言語がある。また、Object Pascal(Borland Delphiで使用される言語)でも対応している。

メモリ[編集]

割り当て[編集]

VLAによって、基本的なメモリ割り当ての問題がユーザーに対して隠蔽される。ヒープ領域スタック領域の間に明確な区別がある環境では、VLAがどちらのメモリ領域に格納されるかは、ユーザーにはわからない[4]

例えば、GNU Cコンパイラは、スタック上にVLAのメモリを割り当てる[5]。Cの他のオブジェクトと同様、VLAはSIZE_MAXバイトに制限されている[6]

変数アクセス[編集]

いくつかのプログラミング言語では、ポインタを介してVLAにアクセスすることができるが、不完全な型と見なされるため、デリファレンス(間接参照)されるとサイズを取得できなくなる[7]

[編集]

次のC99の関数は、指定されたサイズの可変長配列を割り当て、浮動小数点の値で埋めて、別の関数に渡す。配列は自動変数として宣言されているため、read_and_process() から戻るとその存続期間が終了する。

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

    for (int i = 0; i < n; i++)
        vals[i] = read_val();
    return process(n, vals);
}

C99では、関数呼び出しにおける長さのパラメータは、可変長配列のパラメータよりも前に来なければならない[1]

以下はAdaにおける同じ例である。Adaの配列は境界を持っている。従って、長さを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での同等の関数は次の通りである(コンパイル時にプロシージャ・インターフェイスを検査するFortran 90の機能を利用する場合)。

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

一方、関数がFortran 90以前の呼び出しインターフェイスを使用する場合は、まず(外部)関数を宣言し、配列の長さを引数として明示的に渡す必要がある(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のコード断片は、PEOPLE-CNT値で指定された長さ(メンバー数)を持つレコードの可変長配列DEPT-PERSONを宣言する。

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.

次のC#のコード断片は、整数型の可変長配列を宣言する。unsafeというキーワードは、このコードを含むアセンブリが「安全でない」(unsafe) とマークされることを必要とする[8]

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

動的割り当てと自動割り当て[編集]

Java.NET Frameworkなどの言語は、可変長配列を提供するとはみなされない。これらの言語では、全ての配列オブジェクトは論理的にヒープに割り当てられ、配列に関して自動記憶期間というものを持たないためである(JavaとdotNetのコンパイラは、これらのヒープ割り当てを可能な限りスタック上に実際に配置するよう最適化できる)。

脚注[編集]

  1. ^ a b Variable Length Arrays”. 2017年9月21日閲覧。
  2. ^ Variable Length - Using the GNU Compiler Collection (GCC)”. 2017年9月21日閲覧。
  3. ^ ISO 9899:2011 Programming Languages - C 6.7.6.2 4
  4. ^ Variable Length Arrays”. 2017年9月21日閲覧。
  5. ^ Code Gen Options - The GNU Fortran Compiler”. 2017年9月21日閲覧。
  6. ^ §6.5.3.4 and §7.20.3 of the C11 standard (n1570.pdf)
  7. ^ sizeof Operator”. 2017年9月21日閲覧。
  8. ^ より具体的にいうと、アセンブリのコンパイルオプションに "/unsafe" を追加する必要がある。