RECORD 型(構造体)
『Pascal』の RECORD 型は、異なる型のフィールドを一つの複合データとしてまとめる仕組みです。C 言語の struct に相当します。フィールドにはどんな型でも使え、配列や別のレコード型を入れ子にすることもできます。宣言した変数にはドット(.)でフィールドへアクセスします。
構文
{ -----------------------------------------------
RECORD 型の定義(TYPE セクション)
----------------------------------------------- }
type
レコード型名 = record
フィールド名1 : 型1;
フィールド名2 : 型2;
フィールド名3 : 型3;
end;
{ -----------------------------------------------
変数宣言と代入
----------------------------------------------- }
var
変数名 : レコード型名;
begin
変数名.フィールド名1 := 値1;
変数名.フィールド名2 := 値2;
end.
{ -----------------------------------------------
レコードの初期化(定数レコード)
----------------------------------------------- }
const
定数名 : レコード型名 = (
フィールド名1: 値1;
フィールド名2: 値2
);
構文一覧
| 構文 / キーワード | 概要 |
|---|---|
record ... end | レコード型を定義するブロックです。type セクション内で使います。 |
変数.フィールド名 | ドット演算子でレコード変数のフィールドにアクセスします。 |
| フィールドの型 | 整数・実数・文字列・Boolean・列挙型・配列・別のレコード型など任意の型を使えます。 |
| 入れ子レコード | フィールドの型に別のレコード型を指定することでレコードをネストできます。アクセスは 外.内.フィールド のように連鎖します。 |
| 定数レコード | const セクションで レコード型名 = (フィールド名: 値; ...) と書くと読み取り専用の初期値付きレコードを定義できます。 |
| レコードの代入 | rec1 := rec2; で同じ型のレコード変数を丸ごとコピーできます。 |
| 配列との組み合わせ | array[1..N] of レコード型 と宣言するとレコードの配列を作れます。arr[i].フィールド名 でアクセスします。 |
SizeOf(レコード型) | レコード型全体のバイト数を返します。アライメントにより各フィールドのサイズの合計と異なる場合があります。 |
サンプルコード
sg_record.pas
{ sg_record.pas — Pascal の RECORD 型の基本を確認するサンプルです }
{ Steins;Gate のラボメンバーをレコード型で表現します }
{
コンパイルと実行:
fpc sg_record.pas && ./sg_record
}
program sg_record;
{ -----------------------------------------------
ラボメンバーの役割を表す列挙型
----------------------------------------------- }
type
TRole = (
roleMadScientist, { 狂気のマッドサイエンティスト }
roleMoeGirl, { ヒロイン枠(公式設定)}
roleHacker, { 技術担当ハッカー }
roleNeuroscientist, { 神経科学者(未来人)}
roleTimeTraveler { 未来から来たタイムトラベラー }
);
{ -----------------------------------------------
ラボメンバー 1 人分のデータを格納するレコード型
----------------------------------------------- }
TLabMember = record
name : string[40]; { 名前 }
lab_id : Integer; { ラボメンバー番号 }
role : TRole; { 役割 }
ib_number : string[20]; { IBN 5100 解析スキル(メモ文字列)}
is_active : Boolean; { 現在ラボに在籍中かどうか }
end;
{ -----------------------------------------------
全メンバーをまとめる配列の要素数定数
----------------------------------------------- }
const
MEMBER_COUNT = 5;
{ -----------------------------------------------
役割を文字列に変換するヘルパー関数
----------------------------------------------- }
function RoleToStr(r: TRole): string;
begin
case r of
roleMadScientist : RoleToStr := 'Mad Scientist';
roleMoeGirl : RoleToStr := 'Heroine';
roleHacker : RoleToStr := 'Hacker';
roleNeuroscientist: RoleToStr := 'Neuroscientist';
roleTimeTraveler : RoleToStr := 'Time Traveler';
end;
end;
{ -----------------------------------------------
メンバー情報を整形して表示する手続き
----------------------------------------------- }
procedure PrintMember(m: TLabMember);
begin
WriteLn(' No.', m.lab_id, ' ', m.name);
WriteLn(' 役割 : ', RoleToStr(m.role));
WriteLn(' 備考 : ', m.ib_number);
if m.is_active then begin
WriteLn(' 在籍 : 在籍中');
end else begin
WriteLn(' 在籍 : 離脱');
end;
end;
var
{ -----------------------------------------------
ラボメンバー配列の宣言
----------------------------------------------- }
members : array[1..MEMBER_COUNT] of TLabMember;
i : Integer;
copy_rec: TLabMember; { レコードコピーの確認用 }
begin
{ -----------------------------------------------
各メンバーのデータを設定します
----------------------------------------------- }
{ ラボメン 001 — 岡部倫太郎(Rintaro Okabe)}
members[1].name := 'Rintaro Okabe';
members[1].lab_id := 1;
members[1].role := roleMadScientist;
members[1].ib_number := 'Reading Steiner 保持者';
members[1].is_active := True;
{ ラボメン 002 — 椎名まゆり(Mayuri Shiina)}
members[2].name := 'Mayuri Shiina';
members[2].lab_id := 2;
members[2].role := roleMoeGirl;
members[2].ib_number := 'コスプレ担当';
members[2].is_active := True;
{ ラボメン 003 — 橋田至(Itaru Hashida)}
members[3].name := 'Itaru Hashida';
members[3].lab_id := 3;
members[3].role := roleHacker;
members[3].ib_number := 'IBN 5100 解析担当';
members[3].is_active := True;
{ ラボメン 004 — 牧瀬紅莉栖(Kurisu Makise)}
members[4].name := 'Kurisu Makise';
members[4].lab_id := 4;
members[4].role := roleNeuroscientist;
members[4].ib_number := 'タイムリープマシン開発者';
members[4].is_active := True;
{ ラボメン 006 — 阿万音鈴羽(Suzuha Amane)}
members[5].name := 'Suzuha Amane';
members[5].lab_id := 6;
members[5].role := roleTimeTraveler;
members[5].ib_number := 'C204 操縦者(未来人)';
members[5].is_active := False; { 過去に出発済み }
{ -----------------------------------------------
全メンバーの情報を表示します
----------------------------------------------- }
WriteLn('===== Future Gadget Lab メンバー一覧 =====');
for i := 1 to MEMBER_COUNT do begin
PrintMember(members[i]);
WriteLn('');
end;
{ -----------------------------------------------
レコードの丸ごとコピーを確認します
----------------------------------------------- }
WriteLn('--- レコードコピー確認 ---');
copy_rec := members[4]; { 牧瀬紅莉栖のデータをコピー }
copy_rec.name := 'Copy of Kurisu'; { コピー先だけ名前を変更 }
WriteLn(' コピー元 : ', members[4].name);
WriteLn(' コピー先 : ', copy_rec.name);
WriteLn(' コピー元は変更されていません(独立したコピー)');
WriteLn('');
{ -----------------------------------------------
SizeOf でレコードのバイト数を確認します
----------------------------------------------- }
WriteLn('--- SizeOf 確認 ---');
WriteLn(' SizeOf(TLabMember) = ', SizeOf(TLabMember), ' バイト');
WriteLn('==========================================');
end.
fpc sg_record.pas && ./sg_record
Free Pascal Compiler version ...
Linking ./sg_record
===== Future Gadget Lab メンバー一覧 =====
No.1 Rintaro Okabe
役割 : Mad Scientist
備考 : Reading Steiner 保持者
在籍 : 在籍中
No.2 Mayuri Shiina
役割 : Heroine
備考 : コスプレ担当
在籍 : 在籍中
No.3 Itaru Hashida
役割 : Hacker
備考 : IBN 5100 解析担当
在籍 : 在籍中
No.4 Kurisu Makise
役割 : Neuroscientist
備考 : タイムリープマシン開発者
在籍 : 在籍中
No.6 Suzuha Amane
役割 : Time Traveler
備考 : C204 操縦者(未来人)
在籍 : 離脱
--- レコードコピー確認 ---
コピー元 : Kurisu Makise
コピー先 : Copy of Kurisu
コピー元は変更されていません(独立したコピー)
--- SizeOf 確認 ---
SizeOf(TLabMember) = 68 バイト
==========================================
よくあるミス
with 文との競合でどのレコードのフィールドかわからなくなる
with 文を使うと変数名の省略ができますが、複数のレコードを扱うコードでどのフィールドがどのレコードに属するかが読み取りにくくなることがあります。特に入れ子のレコードや複数の with を組み合わせる場合は、明示的にドット記法を使った方が意図が明確になります。
レコード配列の添字が範囲外になる
array[1..N] of レコード型 を宣言した場合、添字は 1 から N が有効です。0 や N+1 へのアクセスはコンパイルエラーにならず実行時エラーや不定動作になります。ループカウンタの初期値・終了値を宣言と合わせることが重要です。
異なるレコード型に同じフィールド名を使って混同する
複数のレコード型に同名のフィールドを定義した場合、代入先の型が異なるとコンパイルエラーになります。型は一致していても別のレコード型同士は互換性がないため、rec1 := rec2 のような代入は同じ型の変数間でのみ行えます。
概要
『Pascal』の RECORD 型はフィールドをドット(.)でアクセスする複合型で、C の struct に相当します。代入演算子 := でレコード全体を丸ごとコピーでき、コピー後のフィールド変更は元のレコードに影響しません(値コピー)。フィールドに別のレコード型を入れ子にしたり、array[1..N] of レコード型 で配列化するなど、柔軟なデータ構造を作れます。RECORD のフィールドアクセスを簡略化する WITH 文については WITH文(レコードフィールドの簡略アクセス) を、同一メモリを複数の型で共有するバリアントレコードについては バリアントレコード(CASE付きRECORD) も合わせて参照できます。ポインタとレコードを組み合わせた動的データ構造の例は ポインタを使ったリンクリストの実装 も参照できます。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。