オープン配列パラメータ(array of)
『Pascal』のオープン配列パラメータは、手続き・関数の引数に『array of 型名』と宣言することで、任意のサイズの配列を受け取れるようにする仕組みです。呼び出し元が渡した配列の長さを『High(引数名)』で取得でき、インデックスは常に『0』から始まります。さらに Free Pascal の『array of const』を使うと、異なる型を混在させた可変長引数を受け取ることもできます。
構文
{ -----------------------------------------------
オープン配列パラメータ(array of 型名)
呼び出し元の配列サイズを問いません
----------------------------------------------- }
procedure 手続き名(arr : array of Integer);
var
i : Integer;
begin
{ インデックスは 0 から High(arr) まで }
for i := 0 to High(arr) do begin
WriteLn(arr[i]);
end;
end;
{ -----------------------------------------------
const / var 修飾子との組み合わせ
const を付けると読み取り専用になります
----------------------------------------------- }
procedure 手続き名(const arr : array of String);
begin
{ arr[0] := 'x'; } { コンパイルエラーになります }
WriteLn(arr[0]);
end;
{ -----------------------------------------------
array of const — 異なる型を混在させた可変長引数
各要素は TVarRec レコードとして渡されます
----------------------------------------------- }
procedure 手続き名(args : array of const);
var
i : Integer;
begin
for i := 0 to High(args) do begin
case args[i].VType of
vtInteger : WriteLn('Integer: ', args[i].VInteger);
vtString : WriteLn('String : ', args[i].VString^);
vtBoolean : WriteLn('Boolean: ', args[i].VBoolean);
end;
end;
end;
{ -----------------------------------------------
呼び出し例
----------------------------------------------- }
var
scores : array[1..3] of Integer;
begin
scores[1] := 90;
scores[2] := 85;
scores[3] := 92;
手続き名(scores); { 固定長配列を渡せます }
手続き名([10, 20, 30]); { 配列コンストラクタでも渡せます }
{ array of const の呼び出し }
手続き名(['Itadori', 185, True]);
end;
構文一覧
| 構文 / 識別子 | 概要 |
|---|---|
procedure P(arr : array of T); | オープン配列パラメータです。任意のサイズの配列を受け取れます。インデックスは常に『0』から始まります。 |
procedure P(const arr : array of T); | 読み取り専用のオープン配列です。手続き・関数内で要素を書き換えようとするとコンパイルエラーになります。 |
High(arr) | オープン配列の最大インデックス(要素数 - 1)を返します。要素数が 0 のときは『-1』を返します。 |
Low(arr) | オープン配列の最小インデックスを返します。オープン配列では常に『0』です。 |
Length(arr) | オープン配列の要素数を返します。『High(arr) + 1』と等価です。 |
[値1, 値2, ...] | 配列コンストラクタです。オープン配列引数に直接リテラルを並べて渡せます。 |
procedure P(args : array of const); | 型混在の可変長引数です。各要素は『TVarRec』型として渡されます。『WriteLn』と同様の引数渡し方が実現できます。 |
TVarRec.VType | 要素の型を示す定数です。『vtInteger』、『vtString』、『vtBoolean』、『vtChar』、『vtAnsiString』などがあります。 |
TVarRec.VInteger | 『VType = vtInteger』のとき、整数値を保持するフィールドです。 |
TVarRec.VString^ | 『VType = vtString』のとき、ショート文字列へのポインタです。『^』でデリファレンスして文字列を取り出します。 |
TVarRec.VAnsiString | 『VType = vtAnsiString』のとき、AnsiString(通常の『String』)へのポインタです。『AnsiString(args[i].VAnsiString)』でキャストして使います。 |
サンプルコード
jjk_open_array.pas
{ jjk_open_array.pas — Pascal のオープン配列と array of const を確認するサンプルです }
{ 呪術廻戦のキャラクターを使って }
{ オープン配列パラメータと可変長引数の動作を確認します }
{
コンパイルと実行:
fpc jjk_open_array.pas && ./jjk_open_array
}
{$mode objfpc}
program jjk_open_array;
{ -----------------------------------------------
手続き①: オープン配列パラメータ(array of Integer)
呪術師の呪力値リストを受け取って合計と平均を計算します
配列のサイズは問いません
----------------------------------------------- }
procedure PrintCurseEnergyStats(const name : String;
const energies : array of Integer);
var
i : Integer;
total : Integer;
begin
total := 0;
WriteLn('--- ', name, ' の呪力値リスト ---');
WriteLn(' 要素数: ', Length(energies));
for i := 0 to High(energies) do begin
WriteLn(' [', i, '] ', energies[i]);
total := total + energies[i];
end;
if Length(energies) > 0 then begin
WriteLn(' 合計 : ', total);
WriteLn(' 平均 : ', total div Length(energies));
end;
WriteLn('');
end;
{ -----------------------------------------------
手続き②: オープン配列パラメータ(array of String)
術式名のリストを受け取って番号付きで表示します
----------------------------------------------- }
procedure ListTechniques(const sorcerer : String;
const techniques : array of String);
var
i : Integer;
begin
WriteLn('--- ', sorcerer, ' の術式 ---');
for i := 0 to High(techniques) do begin
WriteLn(' ', i + 1, '. ', techniques[i]);
end;
WriteLn('');
end;
{ -----------------------------------------------
手続き③: 配列を受け取って最大値のインデックスを返します
var 修飾子で最大値とそのインデックスを呼び出し元に返します
----------------------------------------------- }
procedure FindMaxEnergy(const energies : array of Integer;
var max_val : Integer;
var max_idx : Integer);
var
i : Integer;
begin
max_val := energies[0];
max_idx := 0;
for i := 1 to High(energies) do begin
if energies[i] > max_val then begin
max_val := energies[i];
max_idx := i;
end;
end;
end;
{ -----------------------------------------------
手続き④: array of const — 型混在の可変長引数
キャラクタープロフィールを任意の型の組み合わせで受け取ります
TVarRec.VType で型を判定して表示します
----------------------------------------------- }
procedure PrintProfile(args : array of const);
var
i : Integer;
begin
for i := 0 to High(args) do begin
case args[i].VType of
vtInteger :
WriteLn(' [Integer ] ', args[i].VInteger);
vtBoolean :
WriteLn(' [Boolean ] ', args[i].VBoolean);
vtString :
{ vtString は ShortString へのポインタです。^ でデリファレンスします }
WriteLn(' [String ] ', args[i].VString^);
vtAnsiString :
{ vtAnsiString は AnsiString へのポインタです。キャストして使います }
WriteLn(' [AnsiStr ] ',
AnsiString(args[i].VAnsiString));
vtChar :
WriteLn(' [Char ] ', args[i].VChar);
else
WriteLn(' [Other ] VType=', args[i].VType);
end;
end;
end;
{ -----------------------------------------------
グローバル変数
----------------------------------------------- }
var
{ 虎杖悠仁の呪力値(測定回ごとに変わります) }
itadori_energies : array[1..4] of Integer;
{ 伏黒恵の術式名 }
fushiguro_techniques : array[1..3] of String;
{ 釘崎野薔薇の呪力値 }
kugisaki_energies : array[1..3] of Integer;
best_val : Integer; { 最大呪力値 }
best_idx : Integer; { 最大呪力値のインデックス }
begin
WriteLn('===== 呪術廻戦 オープン配列サンプル =====');
WriteLn('');
{ -----------------------------------------------
固定長配列をオープン配列パラメータに渡します
虎杖悠仁の呪力値リストを設定します
----------------------------------------------- }
itadori_energies[1] := 920;
itadori_energies[2] := 980;
itadori_energies[3] := 1050;
itadori_energies[4] := 1100;
PrintCurseEnergyStats('Yuji Itadori(虎杖悠仁)', itadori_energies);
{ -----------------------------------------------
釘崎野薔薇の呪力値を配列コンストラクタで直接渡します
固定長配列を用意しなくてもリテラルで渡せます
----------------------------------------------- }
PrintCurseEnergyStats('Nobara Kugisaki(釘崎野薔薇)',
[730, 810, 790]);
{ -----------------------------------------------
要素数 1 の配列コンストラクタも渡せます
----------------------------------------------- }
PrintCurseEnergyStats('Nanami Kento(七海建人)', [1200]);
{ -----------------------------------------------
String の配列を渡します
伏黒恵の十種影法術を表示します
----------------------------------------------- }
fushiguro_techniques[1] := '玉犬(白・黒)';
fushiguro_techniques[2] := '嵌合暗翳庭(はめあいあんえいてい)';
fushiguro_techniques[3] := '十種影法術';
ListTechniques('Megumi Fushiguro(伏黒恵)', fushiguro_techniques);
{ 配列コンストラクタで String を渡す例 }
ListTechniques('Satoru Gojo(五条悟)',
['無下限呪術', '蒼(引力)', '赫(斥力)', '紫(虚式)']);
{ -----------------------------------------------
var 引数と組み合わせてオープン配列の最大値を取得します
虎杖悠仁の呪力値から最大値とそのインデックスを探します
----------------------------------------------- }
WriteLn('--- 最大呪力値の探索(FindMaxEnergy) ---');
FindMaxEnergy(itadori_energies, best_val, best_idx);
WriteLn(' Yuji Itadori の最大呪力値: ', best_val,
' インデックス: ', best_idx);
WriteLn('');
{ -------------------------------------------
釘崎野薔薇の呪力値でも同様に確認します
----------------------------------------------- }
kugisaki_energies[1] := 730;
kugisaki_energies[2] := 810;
kugisaki_energies[3] := 790;
FindMaxEnergy(kugisaki_energies, best_val, best_idx);
WriteLn(' Nobara Kugisaki の最大呪力値: ', best_val,
' インデックス: ', best_idx);
WriteLn('');
{ -----------------------------------------------
array of const — 型混在の可変長引数
五条悟のプロフィールを異なる型で渡します
----------------------------------------------- }
WriteLn('--- array of const(PrintProfile) ---');
WriteLn(' Satoru Gojo(五条悟)のプロフィール:');
PrintProfile(['Satoru Gojo', 28, True, '特級術師']);
WriteLn('');
WriteLn(' Kento Nanami(七海建人)のプロフィール:');
PrintProfile(['Kento Nanami', 27, True, '1級術師']);
WriteLn('');
WriteLn('==========================================');
end.
fpc jjk_open_array.pas && ./jjk_open_array Free Pascal Compiler version ... Linking ./jjk_open_array ===== 呪術廻戦 オープン配列サンプル ===== --- Yuji Itadori(虎杖悠仁) の呪力値リスト --- 要素数: 4 [0] 920 [1] 980 [2] 1050 [3] 1100 合計 : 4050 平均 : 1012 --- Nobara Kugisaki(釘崎野薔薇) の呪力値リスト --- 要素数: 3 [0] 730 [1] 810 [2] 790 合計 : 2330 平均 : 776 --- Nanami Kento(七海建人) の呪力値リスト --- 要素数: 1 [0] 1200 合計 : 1200 平均 : 1200 --- Megumi Fushiguro(伏黒恵) の術式 --- 1. 玉犬(白・黒) 2. 嵌合暗翳庭(はめあいあんえいてい) 3. 十種影法術 --- Satoru Gojo(五条悟) の術式 --- 1. 無下限呪術 2. 蒼(引力) 3. 赫(斥力) 4. 紫(虚式) --- 最大呪力値の探索(FindMaxEnergy) --- Yuji Itadori の最大呪力値: 1100 インデックス: 3 Nobara Kugisaki の最大呪力値: 810 インデックス: 1 --- array of const(PrintProfile) --- Satoru Gojo(五条悟)のプロフィール: [AnsiStr ] Satoru Gojo [Integer ] 28 [Boolean ] TRUE [AnsiStr ] 特級術師 Kento Nanami(七海建人)のプロフィール: [AnsiStr ] Kento Nanami [Integer ] 27 [Boolean ] TRUE [AnsiStr ] 1級術師 ==========================================
jjk_vtype_case.pas
TVarRecのVTypeを使って型を判別し、それぞれの型に応じた処理を分ける例です。
{$mode objfpc}
program jjk_vtype_case;
procedure PrintValue(const args : array of const);
var
i : Integer;
begin
for i := 0 to High(args) do begin
case args[i].VType of
vtInteger : WriteLn(' Integer : ', args[i].VInteger);
vtBoolean : WriteLn(' Boolean : ', args[i].VBoolean);
vtChar : WriteLn(' Char : ', args[i].VChar);
vtAnsiString : WriteLn(' String : ', AnsiString(args[i].VAnsiString));
else
WriteLn(' Other (VType=', args[i].VType, ')');
end;
end;
end;
begin
WriteLn('===== VType による型判別 =====');
WriteLn('--- Satoru Gojo(五条悟) ---');
PrintValue(['Satoru Gojo', 28, True]);
WriteLn('');
WriteLn('--- Megumi Fushiguro(伏黒恵) ---');
PrintValue(['Megumi Fushiguro', 15, False]);
WriteLn('==============================');
end.
fpc jjk_vtype_case.pas && ./jjk_vtype_case Free Pascal Compiler version ... Linking ./jjk_vtype_case ===== VType による型判別 ===== --- Satoru Gojo(五条悟) --- String : Satoru Gojo Integer : 28 Boolean : TRUE --- Megumi Fushiguro(伏黒恵) --- String : Megumi Fushiguro Integer : 15 Boolean : FALSE ==============================
jjk_util_format.pas
array of constを受け取るユーティリティ関数の例です。任意の型の値を整形して文字列として返します。
{$mode objfpc}
program jjk_util_format;
uses SysUtils;
function FormatValues(const args : array of const) : String;
var
i : Integer;
result_str : String;
begin
result_str := '';
for i := 0 to High(args) do begin
if i > 0 then result_str := result_str + ', ';
case args[i].VType of
vtInteger : result_str := result_str + IntToStr(args[i].VInteger);
vtBoolean : if args[i].VBoolean then
result_str := result_str + 'true'
else
result_str := result_str + 'false';
vtAnsiString : result_str := result_str + AnsiString(args[i].VAnsiString);
else
result_str := result_str + '?';
end;
end;
FormatValues := '[' + result_str + ']';
end;
begin
WriteLn('===== array of const ユーティリティ関数 =====');
WriteLn(' Yuji Itadori: ', FormatValues(['Yuji Itadori', 15, True]));
WriteLn(' Nobara Kugisaki: ', FormatValues(['Nobara Kugisaki', 16, True]));
WriteLn(' Aoi Todo: ', FormatValues(['Aoi Todo', 18, False]));
WriteLn('=============================================');
end.
fpc jjk_util_format.pas && ./jjk_util_format Free Pascal Compiler version ... Linking ./jjk_util_format ===== array of const ユーティリティ関数 ===== Yuji Itadori: [Yuji Itadori, 15, true] Nobara Kugisaki: [Nobara Kugisaki, 16, true] Aoi Todo: [Aoi Todo, 18, false] =============================================
よくあるミス
vtStringとvtAnsiStringの混同
ShortString型のリテラルは『vtString』、AnsiString型(通常の『String』)は『vtAnsiString』として渡されます。Free Pascalでは文字列リテラルは通常『vtAnsiString』として渡されます。『VType』を確認せずに『VString』フィールドを参照しようとすると、型が一致しない場合にアクセス違反になります。
VString^のデリファレンスを忘れる
『TVarRec.VString』は『PShortString』(ShortStringへのポインタ)です。実際の文字列値を得るには『VString^』のようにポインタを参照外しする必要があります。『VString』をそのまま使おうとするとポインタ値が渡され、意図した文字列にはなりません。
概要
『Pascal』のオープン配列パラメータ(『array of T』)を使うと、呼び出し元がどのサイズの配列を渡しても同じ手続き・関数で処理できます。インデックスは常に『0』始まりに正規化されるため、呼び出し元の配列が『array[1..10]』であっても手続き内では『0』から『9』でアクセスします。『High(arr)』で最大インデックスを、『Length(arr)』で要素数を取得できます。配列コンストラクタ(『[値1, 値2, ...]』)を使えば、固定長配列変数を用意せずにリテラルをそのまま渡すことも可能です。『array of const』は『WriteLn』と同様の「型を問わない可変長引数」を実現する仕組みで、各要素は『TVarRec』レコードとして渡され、『VType』フィールドで型を判定してから対応するフィールドを参照します。配列の基本については 配列(ARRAY)の基本 を、動的配列については 動的配列(Dynamic Array) を、パラメータ渡しの基本については パラメータ渡し(値渡し・VAR引数・CONST引数) を合わせて確認してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。