通常の配列のフィールドを定義するときは、インデックスの範囲、つまり次元ごとのオカレンス数を正確に指定する必要があります。 ランタイムには配列のすべてのフィールドがデフォルトで存在するため、追加の割り当て操作を行うことなく、定義した各オカレンスにアクセスできます。 サイズのレイアウトは変更できません。したがって、フィールドのオカレンスを追加することも削除することもできません。
一方、必要なオカレンス数が開発時にわからないため、ランタイムに配列のフィールド数を柔軟に増減したい場合は、X-array(eXtensible array:拡張可能な配列)と呼ばれているものを使用します。
X-array では、ランタイムにサイズ変更できるため、メモリをより効率よく管理できます。 例えば、大量の配列オカレンスを短期間だけ使用してから、アプリケーションが配列を使用しなくなった時点でメモリを削減することができます。
このドキュメントでは、次のトピックについて説明します。
X-array とは、コンパイル時にオカレンス数を定義しない配列のことです。 X-array は、DEFINE DATA
ステートメント内で、少なくとも 1 つの次元のインデックス範囲に、アスタリスク(*)を使用して定義します。 インデックス定義内のアスタリスク文字(*)は、プログラムの実行時に特定の値を割り当てることができる、変更可能なインデックス範囲を表します。
上限または下限のいずれかのみを可変として定義できます。両方を定義することはできません。
X-array は、(固定の)配列を定義できる場所にならどこにでも、つまり、任意のレベルで、またはインデックス付きのグループとして定義できます。 ただし、データベースビューのMU-/PE- フィールドへのアクセスには使用できません。 複数次元の配列では、定数と変更可能な境界を組み合わせて使用できます。
例:
DEFINE DATA LOCAL 1 #X-ARR1 (A5/1:*) /* lower bound is fixed at 1, upper bound is variable 1 #X-ARR2 (A5/*) /* shortcut for (A5/1:*) 1 #X-ARR3 (A5/*:100) /* lower bound is variable, upper bound is fixed at 100 1 #X-ARR4 (A5/1:10,1:*) /* 1st dimension has a fixed index range with (1:10) END-DEFINE /* 2nd dimension has fixed lower bound 1 and variable upper bound
X-array のオカレンス数は、アクセスする前に明示的に割り当てる必要があります。 次元のオカレンス数を増減するには、EXPAND
、RESIZE
、REDUCE
の各ステートメントを使用します。
ただし、X-array の次元数(1、2、または 3 次元)は変更できません。
例:
DEFINE DATA LOCAL 1 #X-ARR(I4/10:*) END-DEFINE EXPAND ARRAY #X-ARR TO (10:10000) /* #X-ARR(10) to #X-ARR(10000) are accessible WRITE *LBOUND(#X-ARR) /* is 10 *UBOUND(#X-ARR) /* is 10000 *OCCURRENCE(#X-ARR) /* is 9991 #X-ARR(*) := 4711 /* same as #X-ARR(10:10000) := 4711 /* resize array from current lower bound=10 to upper bound =1000 RESIZE ARRAY #X-ARR TO (*:1000) /* #X-ARR(10) to #X-ARR(1000) are accessible /* #X-ARR(1001) to #X-ARR(10000) are released WRITE *LBOUND(#X-ARR) /* is 10 *UBOUND(#X-ARR) /* is 1000 *OCCURRENCE(#X-ARR) /* is 991 /* release all occurrences REDUCE ARRAY #X-ARR TO 0 WRITE *OCCURRENCE(#X-ARR) /* is 0
X-group 配列のオカレンス数を増減する場合、独立した次元と従属した次元を区別する必要があります。
直接指定されている(継承していない)X-group 配列または X-array の次元は、独立しています。
直接指定されていない(上位の配列から継承している)X-group 配列または X-array の次元は、従属しています。
X-array の独立した次元のみ、EXPAND
、RESIZE
、REDUCE
の各ステートメントで変更できます。次元の変更は、その次元を独立した次元として所有している X-group 配列の名前を使用して行う必要があります。
DEFINE DATA LOCAL 1 #X-GROUP-ARR1(1:*) /* (1:*) 2 #X-ARR1 (I4) /* (1:*) 2 #X-ARR2 (I4/2:*) /* (1:*,2:*) 2 #X-GROUP-ARR2 /* (1:*) 3 #X-ARR3 (I4) /* (1:*) 3 #X-ARR4 (I4/3:*) /* (1:*,3:*) 3 #X-ARR5 (I4/4:*, 5:*) /* (1:*,4:*,5:*) END-DEFINE
以下の表は、上記のプログラム内の各次元が独立しているのか従属しているのかを示しています。
名前 | 従属した次元 | 独立した次元 |
---|---|---|
#X-GROUP-ARR1 |
(1:*) |
|
#X-ARR1 |
(1:*) |
|
#X-ARR2 |
(1:*) |
(2:*) |
#X-GROUP-ARR2 |
(1:*) |
|
#X-ARR3 |
(1:*) |
|
#X-ARR4 |
(1:*) |
(3:*) |
#X-ARR5 |
(1:*) |
(4:*,5:*) |
従属した次元に使用できる添字表記は、単一のアスタリスク(*)、アスタリスクで定義した範囲(*:*)、または定義済みの添字範囲のみです。
これは、従属した次元の境界は変更できないことを示しています。
従属した次元のオカレンス数は、対応するグループ配列を操作することによってのみ変更できます。
EXPAND ARRAY #X-GROUP-ARR1 TO (1:11) /* #X-ARR1(1:11) are allocated /* #X-ARR3(1:11) are allocated EXPAND ARRAY #X-ARR2 TO (*:*, 2:12) /* #X-ARR2(1:11, 2:12) are allocated EXPAND ARRAY #X-ARR2 TO (1:*, 2:12) /* same as before EXPAND ARRAY #X-ARR2 TO (* , 2:12) /* same as before EXPAND ARRAY #X-ARR4 TO (*:*, 3:13) /* #X-ARR4(1:11, 3:13) are allocated EXPAND ARRAY #X-ARR5 TO (*:*, 4:14, 5:15) /* #X-ARR5(1:11, 4:14, 5:15) are allocated
EXPAND
ステートメントは、任意の順序で記述できます。
従属した次元しか配列にないため、以下のような EXPAND
ステートメントは使用できません。
EXPAND ARRAY #X-ARR1 TO ... EXPAND ARRAY #X-GROUP-ARR2 TO ... EXPAND ARRAY #X-ARR3 TO ...
X-array のオカレンス数は、アクセスする前に EXPAND
ステートメントまたは RESIZE
ステートメントを使用して、明示的に割り当てる必要があります。
一般的なルールとして、存在しない X-array のオカレンスにアクセスしようとするとランタイムエラーが発生します。 ただし、ステートメントの中には、全体範囲表記(#X-ARR(*)
など)を使用して X-array のすべてのオカレンスを参照する場合は、実体を持たない X-array フィールドにアクセスしてもエラーにならないものがあります。 これは、以下に対して適用されます。
CALL
ステートメント内で使用されているパラメータ
オプションパラメータとして定義されている場合は、CALLNAT
、PERFORM
、OPEN DIALOG
の各ステートメント内で使用されているパラメータ
COMPRESS
ステートメント内で使用されているソースフィールド
PRINT
ステートメント内で指定されている出力フィールド
RESET
ステートメント内で参照されているフィールド
これらのステートメントの 1 つを使用して実体を持たない X-array のオカレンスを個別に参照すると、対応するエラーメッセージが発行されます。
例:
DEFINE DATA LOCAL 1 #X-ARR (A10/1:*) /* X-array only defined, but not allocated END-DEFINE RESET #X-ARR(*) /* no error, because complete field referenced with (*) RESET #X-ARR(1:3) /* runtime error, because individual occurrences (1:3) are referenced END
配列参照のアスタリスク(*)表記は、次元のすべての範囲を表します。 配列が X-array の場合、アスタリスクは、現在割り当てられている下限および上限のインデックス範囲を表します。この下限および上限は、*LBOUND
および *UBOUND
によって確認できます。
X-array をパラメータとして使用すると、以下の整合性チェックで定数の配列のように扱われます。
フォーマット
長さ
次元
オカレンス数
また、X-array パラメータは、ステートメント RESIZE
、REDUCE
、または EXPAND
を使用することにより、オカレンス数を変更することもできます。 X-array パラメータのサイズ変更が可能かどうかは、以下の 3 つの要素によって決まります。
使用するパラメータ引き渡しのタイプ(参照渡しまたは値渡し)
呼び出し元または X-array パラメータの定義
引き渡す X-array の範囲のタイプ(全体または一部)
以下の表は、X-array パラメータに EXPAND
、RESIZE
、REDUCE
の各ステートメントを適用できる条件を示しています。
呼び出し元 | パラメータ | ||
---|---|---|---|
スタティック | 変数(1:V) | X-array | |
スタティック | × | × | ○ |
X-array の一部。例:CALLNAT...#XA(1:5) |
× | × | ○ |
X-array 全体。例:CALLNAT...#XA(*)
|
× | × | ○ |
呼び出し元 | パラメータ | |||
---|---|---|---|---|
スタティック | 変数(1:V) | 固定の下限を持つ X-array。例: DEFINE DATA PARAMETER 1 #PX (A10/1:*) |
固定の上限を持つ X-array。例: DEFINE DATA PARAMETER 1 #PX (A10/*:1) |
|
スタティック | × | × | × | × |
X-array の一部。例: CALLNAT...#XA(1:5) |
× | × | × | × |
固定の下限を持つ X-array の全体。例: DEFINE DATA LOCAL 1 #XA(A10/1:*) ... CALLNAT...#XA(*) |
× | × | ○ | × |
固定の上限を持つ X-array の全体。例: DEFINE DATA LOCAL 1 #XA(A10/*:1) ... CALLNAT...#XA(*) |
× | × | × | ○ |
X-group 配列の宣言は、グループの各要素が同じ上限および下限を持つことを暗黙的に意味します。 したがって、X-group 配列フィールドの従属した次元のオカレンス数は、RESIZE
、REDUCE
、EXPAND
の各ステートメントで X-group 配列のグループ名を指定したときにのみ変更できます(前述の「X-Group 配列のストレージ管理」を参照)。
X-group 配列のメンバは、パラメータデータエリアに定義されている X-group 配列にパラメータとして引き渡すことができます。 呼び出す側と呼び出される側のグループ構造は必ずしも同一である必要はありません。 呼び出した側の X-group
配列に矛盾がない限り、呼び出された側は RESIZE
、REDUCE
および EXPAND
を実行できます。
プログラム:
DEFINE DATA LOCAL 1 #X-GROUP-ARR1(1:*) /* (1:*) 2 #X-ARR1 (I4) /* (1:*) 2 #X-ARR2 (I4) /* (1:*) 1 #X-GROUP-ARR2(1:*) /* (1:*) 2 #X-ARR3 (I4) /* (1:*) 2 #X-ARR4 (I4) /* (1:*) END-DEFINE ... CALLNAT ... #X-ARR1(*) #X-ARR4(*) ... END
サブプログラム:
DEFINE DATA PARAMETER 1 #X-GROUP-ARR(1:*) /* (1:*) 2 #X-PAR1 (I4) /* (1:*) 2 #X-PAR2 (I4) /* (1:*) END-DEFINE ... RESIZE ARRAY #X-GROUP-ARR to (1:5) ... END
サブプログラムの RESIZE
ステートメントは実行できません。 プログラムの X-group 配列で定義されているフィールドのオカレンス数と矛盾しています。
ダイナミック変数の X-array の割り当てでは、最初に EXPAND
ステートメントを使用してオカレンス数を指定し、後でそのオカレンス数に値を割り当てることによって変更できます。
DEFINE DATA LOCAL 1 #X-ARRAY(A/1:*) DYNAMIC END-DEFINE EXPAND ARRAY #X-ARRAY TO (1:10) /* allocate #X-ARRAY(1) to #X-ARRAY(10) with zero length. /* *LENGTH(#X-ARRAY(1:10)) is zero #X-ARRAY(*) := 'abc' /* #X-ARRAY(1:10) contains 'abc', /* *LENGTH(#X-ARRAY(1:10)) is 3 EXPAND ARRAY #X-ARRAY TO (1:20) /* allocate #X-ARRAY(11) to #X-ARRAY(20) with zero length /* *LENGTH(#X-ARRAY(11:20)) is zero #X-ARRAY(11:20) := 'def' /* #X-ARRAY(11:20) contains 'def' /* *LENGTH(#X-ARRAY(11:20)) is 3
システム変数 *LBOUND
および *UBOUND
には、指定した次元(1、2、または 3 次元。複数指定可)に対する配列の、その時点での下限および上限が設定されます。
X-array にオカレンスが割り当てられていない場合、*LBOUND
または *UBOUND
は未定義のため、アクセスするとランタイムエラーが発生します。 ランタイムエラーを回避するには、*LBOUND
または *UBOUND
を評価する前に *OCCURRENCE
を使用して、オカレンス数がゼロかどうかを確認します。
例:
IF *OCCURRENCE (#A) NE 0 AND *UBOUND(#A) < 100 THEN ...