Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2014年02月17日] [更新 2019年04月30日] Delphi 一般・その他
   
変数やオブジェクトの初期値
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro
[整理番号 - 0640]







01_変数やオブジェクトの初期値


変数の初期値には注意が必要です.
グローバル変数は,ポイント型とオブジェクト型の場合,nil に初期化されます.数値は 0 に初期化されます.1 文字の型である Char 型の変数は Null 文字に初期化されます.一方,イベントやメソッド内で定義したそれらのローカル変数は初期化されません.
string 型の文字列変数は,グローバル変数もローカル変数も長さ 0 の空文字となります.

下図はクラス変数の場合です.クラス変数もグローバル変数ですから初期化されます.



図1
クラス型変数の初期値

リスト1
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TMyClass = class
  public
    class var
    FHogeInt    : Integer;
    FHogeButton : TButton;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  クラス型変数の初期値を確認
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LText : String;
begin
  LText := 'FHogeInt は ' + IntToStr(TMyClass.FHogeInt) + ' です';

  if TMyClass.FHogeButton = nil then begin
    LText := LText + sLineBreak + 'FHogeButton は nil です';
  end else begin
    LText := LText + sLineBreak + 'FHogeButton は nil ではありません';
  end;

  MessageBox(0, PChar(LText), '結果', MB_ICONINFORMATION);
end;

end.


以下はローカル変数の場合を確認した結果です.テストに使用したコードは,ローカル変数として整数を定義していますが,その値は,下図のように,0 とはなりません.


図2
ローカルな整数型の変数の,初期化されていない値の例

リスト2
procedure TForm1.Button1Click(Sender: TObject);
var
  Value : Integer;
begin
  MessageBox(0, PChar(IntToStr(Value)), '情報', MB_OK);
end;


次のコードは,TButton オブジェクトの変数をローカル変数として定義しています.
このコードを実行しても,TButton オブジェクトの実体 (インスタンス) は nil としては検出できません.もちろん Assigned(aBtn) は True となります.


図3
ローカルなオブジェクトが初期化されていない場合

上のダイアログを閉じると,下図のように例外が発生します.
これは,aBtn が生成されていないので,aBtn というオブジェクトのインスタンス (実体) は存在しません.その存在しないオブジェクトに対して操作したために発生します.
もし,aBtn が nil の場合,nil のオブジェクトに対する操作では例外も何も発生しません.


図4
生成されていないオブジェクトを操作すると例外が発生する

リスト3
procedure TForm1.Button1Click(Sender: TObject);
var
  aBtn : TButton;
begin
  if aBtn = nil then begin
    MessageBox(0, 'nil です', '情報', MB_OK);
  end;

  if aBtn <> nil then begin
    MessageBox(0, 'nil ではありません', '情報', MB_OK);
  end;

  //ここで例外が発生する
  //aBtnがnilの場合はエラーにならないが,操作は無効となる
  aBtn.Caption := 'ABC';
end;




02_初期化されていない可能性があります


通常は,上のコードをコンパイルすると,次のような警告が表示されます.
オブジェクトのインスタンスを生成するコードが存在する場合,この表示が現れるかどうかは,オブジェクトのインスタンスを生成するコードを書く位置にもよります.

[DCC 警告] Unit1.pas(63): W1036 変数 'aBtn' が初期化されていない可能性があります


次のコードも「初期化されていない可能性があります」の警告が表示されます.
ローカル変数は初期化されません.このコードでは LIntB に値が代入されない場合があります.したがって,LIntC の値も不定値になってしまうことがあります.これを避けるには,LIntB に何らかの初期値を代入しておきます.あるいは,条件分岐に else を追加して LIntB に,必ず値がセットされるようにします.

上のコードもこのコードも,短いコードですから,すぐに判断できますが,実際のアプリ開発でこのようなコーディングをしてしまうと,予期しない結果となる可能性があります.


[DCC 警告] Unit1.pas(37): W1036 変数 'LIntB' が初期化されていない可能性があります

リスト4
procedure TForm1.Button1Click(Sender: TObject);
var
  LIntA : Integer;
  LIntB : Integer;
  LIntC : Integer;
begin
  LIntA := 100;
  if LIntA > 100 then begin
    LIntB := 200;
  end;
  //上の条件に合わない時にLIntBを使用すると問題が発生する可能性がある
  LIntC := LIntB;
end;


上のコードのようにローカルな処理の最初に変数に初期値を代入すると,以下のようなヒントが表示されることがあります.この現象は,Delphi のパーションやコーディングにもよるようです.実際にその変数が使われていても表示さることがあります.


[DCC ヒント] Unit1.pas(30): H2077 'LIntA' に代入された値は使われていません




03_文字列関係変数の初期値


String 型の文字列変数は,グローバル変数もローカル変数も長さ 0 の空文字となります.
問題は文字列の領域を確保したり長さを設定したりする場合です.Windwos API の関数類を使用する際には必要となることがあります.
領域を確保しただけとか,長さを設定しただけだと,いわゆる「ゴミ」が入ることがあります.これはメモリ上の不定な領域の値なので,いつも同じ値とは限りません.また,全く入らないか,制御文字等の場合は表示されません.



[備考 1]
文字列やテキストを扱う Windows API の関数類では,引数の値の設定によって,必要なバッファのサイズ (バイト数または文字数) が取得できることがあります.
そのバッファのサイズで文字列の長さを設定してから,実際にその Windows API で目的の文字列等を扱ったり取得ができます.,


[備考 2]
結果の文字列の「ゴミ」は,下に示すコードの実行結果の場合です.実際に「ゴミ」が入るかどうかは,領域を確保した後にどんな処理をするかにもよります.



SetLength 手続きで String 型の文字列を格納するメモリ領域を確保する場合です.
SetLength 手続きは確保したメモリ領域を初期化しません.FillChar 手続きを使用すると初期化できます.FillChar 手続きの第 1 引数には String 型の文字列の最初の文字を指定します.文字のインデックスを指定しないで変数を渡すと,String 型の変数として機能しなくなります.



図5
SetLength で String 型の変数用のメモリを確保
  • 確保したメモリは初期化されない
図6
SetLength で String 型の変数用のメモリを確保
  • FillChar 手続きを使用して初期化した結果

リスト5
//=============================================================================
//  SetLength で確保した String 型の変数の値は未定義状態
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LString : string;
  LIndex  : Integer;
begin
  Memo1.Lines.Clear;
  Memo1.Lines.BeginUpdate;

  SetLength(LString, 100);

  Memo1.Lines.Add(LString);
  for LIndex := 1 to Length(LString) do begin
    Memo1.Lines.Add(IntToStr(LIndex) + ' : ' + LString[LIndex]);
  end;

  Memo1.Lines.EndUpdate;
end;

//=============================================================================
//  SetLength で確保した String 型の変数の初期化
//  FillChar 手続きを使用して初期化できる
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LString : string;
  LIndex  : Integer;
begin
  Memo1.Lines.Clear;
  Memo1.Lines.BeginUpdate;

  SetLength(LString, 100);

  // インデックス 1 を指定して初期化する
  // インデックスを指定しないと String 型の変数として機能しなくなる
  FillChar(LString[1], Length(LString) * SizeOf(Char), #0);

  Memo1.Lines.Add(LString);
  for LIndex := 1 to Length(LString) do begin
    Memo1.Lines.Add(IntToStr(LIndex) + ' : ' + LString[LIndex]);
  end;

  Memo1.Lines.EndUpdate;
end;


PChar 型の文字列変数用のメモリを確保する場合です. AllocMem 関数を使用してメモリ領域を確保すると,そのメモリ領域を初期化してくれます.
ZeroMemory 手続きや FillChar 手続きを使用すると,確保したメモリ領域を初期化できます.



図7
PChar 型の文字列変数用のメモリの確保
  • StrAlloc 関数を使用した場合
  • メモリは初期化されない
図8
PChar 型の文字列変数用のメモリの確保
  • AllocMem 関数を使用した場合
  • 確保したメモリが初期化される

リスト6
//=============================================================================
//  PChar 型の変数のメモリの確保に StrAlloc 関数を使用した場合
//  確保したメモリ領域は初期化されない
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LPChar : PChar;
  LLen   : Integer;
  LIndex : Integer;
begin
  Memo1.Lines.Clear;
  Memo1.Lines.BeginUpdate;

  LLen := 100;

  // メモリの確保 (+1 は Null 終端文字用)
  LPChar := StrAlloc(LLen + 1);
  try
   // 途中で初期化したい場合は以下のどちらかを実行
   // ZeroMemory(LPChar, (LLen + 1) * SizeOf(Char));
   // FillChar(LPChar[0], (LLen + 1) * SizeOf(Char), #0);

    Memo1.Lines.Add(LPChar);
    for LIndex := 0 to LLen - 1 do begin
      Memo1.Lines.Add(IntToStr(LIndex) + ' : ' + LPChar[LIndex]);
    end;
  finally
    StrDispose(LPChar);
  end;

  Memo1.Lines.EndUpdate;
end;

//=============================================================================
//  PChar 型の変数のメモリの確保に AllocMemc 関数を使用した場合
//  確保したメモリ領域が初期化される
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LPChar : PChar;
  LLen   : Integer;
  LIndex : Integer;
begin
  Memo1.Lines.Clear;
  Memo1.Lines.BeginUpdate;

  LLen := 100;

  // メモリの確保 (+1 は Null 終端文字用)
  LPChar := AllocMem((LLen + 1) * SizeOf(Char));
  try
   // 途中で初期化したい場合は以下のどちらかを実行
   // ZeroMemory(LPChar, (LLen + 1) * SizeOf(Char));
   // FillChar(LPChar[0], (LLen + 1) * SizeOf(Char), #0);

    Memo1.Lines.Add(LPChar);
    for LIndex := 0 to LLen - 1 do begin
      Memo1.Lines.Add(IntToStr(LIndex) + ' : ' + LPChar[LIndex]);
    end;
  finally
    FreeMem(LPChar);
  end;

  Memo1.Lines.EndUpdate;
end;




04_const 修飾子と型付き定数による初期化 - 値が変更できる定数


一般的に,ローカルな変数は,その変数を使用する前に,一定の値を代入したりして初期化しておくと確実です.また,オブジェクト型の場合は nil を代入しておくと,そのオブジェクトが nil かどうかを判定することができます.

const 修飾子を使用すると変数を初期化できます.ただし,これは厳密には変数とは言えません.定数値です.次のような型付き定数を使用すると,初期値が設定でき,実行時にもその値を変数することができます.変更可能な定数ということになります.
型付き定数の値を変更可能にするには,コンパイラ指令の {$WRITEABLECONST ON} または {$J+} が必要です.型付き定数の値を変更しないようにするには,{$WRITEABLECONST OFF} または {$J-} を指定します.これがデフォルトのコンパイラ指令となっています.



リスト7
//通常の定数(const修飾子)
const
  ID_Valuea = 100;

{$WRITEABLECONST ON}
//型付き定数
const
  ID_Value : Integer = 100;
  ID_Array : array[0..3] of Integer = (10, 20, 30, 40);
{$WRITEABLECONST OFF}


値の変更が可能な,型付き定数を使用する例です.
ID_Value という型付き定数の初期値は 100 ですが,実行時に 500 という値にしています.


図9
下のコードの実行結果

リスト8
implementation

{$R *.dfm}

{$WRITEABLECONST ON}

//=============================================================================
//  型付き定数を使用した変数の初期化
//  {$WRITEABLECONST ON}または{$J+}指令を使用すると型付き定数の値が変更できる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
const
  ID_Value : Integer = 100;
var
  LText : String;
begin
  ID_Value := 500;
  LText    := IntToStr(ID_Value);

  MessageBox(Handle, PChar(LText), '結果', MB_ICONINFORMATION);
end;


型付き定数は,その値を実行時に変更すると,たとえローカルな型付き定数であっても,その値を保持するようになっています.このことを利用したテストです.
このコードは,ボタンをクリックすると,定義した型付き定数の値をインクリメントして,そのクリック回数をボタンの Caption とします.回数は 10 回まで数えます.


図10
実行開始時の画面
図11
Button1 を 4 回クリックした結果
図12
Button1 を 11 回以上クリックした結果

リスト9
implementation

{$R *.dfm}

{$WRITEABLECONST ON}

//=============================================================================
//  型付き定数を使用したサンプル
//
//  型付き定数は値の変更が可能
//  型付き定数の値がローカル内でも保持されることを利用したカウンタの例
//  ボタンクリックの回数を調べる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
const
  ID_Value : Integer = 0;
begin
  Inc(ID_Value);

  if ID_Value > 10 then begin
    Button1.Caption := 'クリック数が 10 回を超えています';
  end else begin
    Button1.Caption := 'クリック回数 : ' + IntToStr(ID_Value);
  end;
end;




05_const 修飾子と型付き定数を使用したトグル操作ボタン


チェックボックスのようなトグル機能のボタンは,次のように,const 修飾子と型付き定数を利用して実装することができます.このコードはボタンクリックのイベント内にトグル状態を保持する変数がありますから,コードの見通しがいいと言えます.

トグル状態をプログラムの他の場所で使用する必要がある場合は,フラグ用の Boolean 型 (論理型) のグローバル変数を用意して現在の状態をセットしておきます.そうすればその変数の値で現在の状態を判定できます.



図13
EXE 起動時の状態
図14
ボタンをクリックすると状態が変わる
  • もう一度クリックすると上の図と同じになる

リスト10
//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.Caption := 'switch ON';
end;

//=============================================================================
//  const 修飾子と型付き定数を使用したトグルボタン
//=============================================================================
{$WRITEABLECONST ON}
procedure TForm1.Button1Click(Sender: TObject);
const
  LToggleON : Boolean = False;
begin
  if not LToggleON then begin
    Button1.Caption := 'switch OFF';
  end else begin
    Button1.Caption := 'switch ON';
  end;

  //トグル
  LToggleON := not LToggleON;
end;
{$WRITEABLECONST OFF}




06_クラスのメンバーではないグローバル変数の初期化


次のように,クラスのメンバーではないグローバル変数は,定義の時に初期化できます.



図15
クラスのメンバでない変数は初期化できる

リスト11
implementation

{$R *.dfm}

var
  FValue : Integer = 100;

//=============================================================================
//  クラスのメンバでないグローバルな変数の操作
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  FValue := FValue + 300;
  MessageBox(Handle, PChar(IntToStr(FValue)), '結果', MB_ICONINFORMATION);
end;




07_静的配列の要素の初期化と初期値設定


Char 方の文字配列は,上のサンプルでも使用している FillChar 手続きで初期化できます・
一般的に,配列の要素の値は,for next 等のループで初期化できますが,要素の値を全て 0 に初期化するのであれば ZeroMemory 手続きが利用できます.
ZeroMemory 手続きによる初期化は,静的配列でも動的配列でも使用できます.

ZeroMemory の第 2 引数には,その配列が使用しているバイト数を指定します.そのバイト数には,配列の要素数に,変数の型のバイトサイズを乗算した値を使用します.配列の要素数は Length 関数で取得できます.また,変数の型のバイトサイズは SizeOf 関数で取得できます.



図16
整数型の静的配列の要素を全て 0 にする

リスト12
//=============================================================================
//  整数型の静的配列の値を全て0にする
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LData  : array[0..4] of Integer;
  LIndex : Integer;
begin
  ListBox1.Items.Clear;
  ListBox1.Items.BeginUpdate;

  //値を代入
  LData[0] := 0;
  LData[1] := 100;
  LData[2] := 200;
  LData[3] := 300;
  LData[4] := 400;

  //全ての要素を0にする
  //実は単にメモリの値を0にする操作
  ZeroMemory(@LData[0], Length(LData) * SizeOf(Integer));

  //確認表示
  for LIndex := Low(LData) to High(LData) do begin
    ListBox1.Items.Add(Format('%6d', [LData[LIndex]]));
  end;

  ListBox1.Items.EndUpdate;
end;


グローバル変数として定義するか,型付き定数として定義した場合は,配列の各要素の値の初期値を設定できます.



図17
グローバル変数で定義した配列要素の値を取得
図18
型付き定数で定義した配列の要素の値を取得

リスト13
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)

    Button1: TButton;
    Button2: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  FData : array[0..4] of Integer = (0, 100, 200, 300, 400);

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  ListBox1.Font.Name := 'Courier New';
  ListBox1.Font.Size := 10;
end;

//=============================================================================
//  グローバルな配列変数の要素を取得して表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  i : Integer;
begin
  ListBox1.Items.Clear;
  ListBox1.Items.BeginUpdate;

  for i := Low(FData) to High(FData) do begin
    ListBox1.Items.Add(Format('%6d', [FData[i]]));
  end;

  ListBox1.Items.EndUpdate;
end;

//=============================================================================
//  ローカルな配列変数の要素を取得して表示
//  constで定義すれば配列要素の値を初期設定可能
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
const
  LData : array[0..4] of Integer = (0, 10, 20, 30, 40);
var
  i : Integer;
begin
  ListBox1.Items.Clear;
  ListBox1.Items.BeginUpdate;

  for i := Low(LData) to High(LData) do begin
    ListBox1.Items.Add(Format('%6d', [LData[i]]));
  end;

  ListBox1.Items.EndUpdate;
end;

end.




08_動的配列の要素の初期化と配列の初期化


動的配列は,SetLength 手続きで要素数を確保するとデフォルトの値に初期化されます.ただし,それは初回だけです.2 回目以降の挙動についてはオンラインヘルプで確認してください.

型宣言の動的配列であれば,InitializeArray 関数を使用して,その要素の値を初期化できます.ただし,値の指定はありません.デフォルトの初期値である 0 となります.上の静的配列の初期化のサンプルで使用した ZeroMemory 手続きでも 0 に初期化できます.
下に示すコードは,TIntegerDynArray 型の整数配列の各要素の値を全て 0 にする例です.



図19
動的配列の要素の初期化例
  • 各要素に値を代入した後,初期化したので全ての要素の値が 0 になっている

リスト14
//=============================================================================
//  配列要素の初期化
//  InitializeArray関数を使用
//
//  TIntegerDynArrayの使用にはusesにTypesが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  Array1 : TIntegerDynArray;
  i      : Integer;
begin
  Memo1.Lines.Clear;

  //サイズを設定して各要素に値を代入
  SetLength(Array1, 10);
  for i := Low(Array1) to High(Array1) do begin
    Array1[i] := i;
  end;

  //配列の要素を初期化(全て0になる)
  //InitializeArrayは要素数の設定はしないので注意
  InitializeArray(Array1, TypeInfo(TIntegerDynArray), Length(Array1));

  //確認表示
  for i := Low(Array1) to High(Array1) do begin
    Memo1.Lines.Add(IntToStr(i) + ' --  ' + IntToStr(Array1[i]));
  end;
end;


動的配列のメモリの解放操作は特に必要ありませんが,明示的に解放するのであれば Finalize 関数が使用できます.
Finalize 関数は,配列が確保したメモリ領域を解放し,要素数を 0 にします.つまり,配列要素が設定されていない初期の状態にします.



図20
動的配列を初期化すると要素数は 0 となる

リスト15
//=============================================================================
//  動的に割り当てた変数の初期化(1)
//  Finalize関数を使用
//  型宣言の動的配列
//
//  TIntegerDynArrayの使用にはusesにTypesが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  Array1 : TIntegerDynArray;
begin
  Memo1.Lines.Clear;

  //配列の要素数を設定
  SetLength(Array1, 10);
  Memo1.Lines.Add('要素数 : ' + IntTostr(Length(Array1)));

  //配列の初期化(要素のサイズは0になる)
  Finalize(Array1);
  Memo1.Lines.Add('要素数 : ' + IntTostr(Length(Array1)));
end;

//=============================================================================
//  動的に割り当てた変数の初期化(2)
//  型宣言でない動的配列
//  Finalize関数を使用
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  Array1 : array of Integer;
begin
  Memo1.Lines.Clear;

  //配列の要素数を設定
  SetLength(Array1, 10);
  Memo1.Lines.Add('要素数 : ' + IntTostr(Length(Array1)));

  //配列の初期化(要素のサイズは0になる)
  Finalize(Array1);
  Memo1.Lines.Add('要素数 : ' + IntTostr(Length(Array1)));
end;


動的配列では,そのコンストラクタで,動的配列要素の確保と同時に初期値の設定が可能です.






09_バイト型配列 ( TBytes ) の要素の初期化


TBytes 型のバイト配列の要素も ZeroMemory 手続きを使用して初期化できます.この場合の初期化は,配列要素の各バイト値を全て $00 にします.FillMemory 手続きを使用すると全ての要素の値を $00 以外の同じ値にできます.

配列が使用しているバイト数 (メモリサイズ) は,静的配列であれば SizeOf 関数で取得できます.動的配列の場合は,SizeOf 関数で取得した値は配列の型のサイズになります.動的配列の変数はポインタですから,これはポインタのサイズです.したがって,32 ビットの EXE では 4, 64 ビットの EXE てば 8 になります.
動的なバイト配列が使用しているバイト数は Length 関数で取得できます.

動的配列の要素数を SetLength 手続きで設定した場合,配列の要素は 0 または nil に初期化されます.バイト配列の場合は全ての要素の値が 0 になります.



図21
バイト型配列の要素の初期化
  • 各要素の値を $EE にした例

リスト16
//=============================================================================
//  バイト配列の初期化(全ての要素を 0にする)
//  動的配列の場合
//  ZeroMemory手続きを使用する例
//
//  ZeroMemory手続きにはLength 関数で取得したバイト長さを与える
//  動的配列の場合,SizeOf で取得した値は型のサイズになる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LArrBytes : TBytes;
  LIndex    : Integer;
begin
  Memo1.Lines.Clear;

  SetLength(LArrBytes, 10);

  // 初期化確認用に要素に値をセット
  for LIndex := Low(LArrBytes) to High(LArrBytes) do begin
    LArrBytes[LIndex] := Byte(LIndex + 1);
  end;

  // 配列の要素を初期化(全て0になる)
  ZeroMemory(@LArrBytes[0], Length(LArrBytes));

  // 初期化後の各要素の値を確認表示
  for LIndex := Low(LArrBytes) to High(LArrBytes) do begin
    Memo1.Lines.Add('$' + IntToHex(LArrBytes[LIndex], 2));
  end;

  Memo1.Lines.Add('SizeOf : '+ IntToStr(SizeOf(LArrBytes)));
  Memo1.Lines.Add('Length : '+ IntToStr(Length(LArrBytes)));
end;

//=============================================================================
//  バイト配列の初期化(全ての要素を同じ値にする)
//  動的配列の場合
//  FillMemory手続きを使用する例
//
//  FillMemory手続きにはLength 関数で取得したバイト長さを与える
//  動的配列の場合,SizeOf で取得した値は型のサイズになる
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LArrBytes : TBytes;
  LIndex    : Integer;
begin
  Memo1.Lines.Clear;

  SetLength(LArrBytes, 10);

  // 初期化確認用に要素に値をセット
  for LIndex := Low(LArrBytes) to High(LArrBytes) do begin
    LArrBytes[LIndex] := Byte(LIndex + 1);
  end;

  // 配列の要素を初期化(全て同じ値になる)
  FillMemory(@LArrBytes[0], Length(LArrBytes), $EE);

  // 初期化後の各要素の値を確認表示
  for LIndex := Low(LArrBytes) to High(LArrBytes) do begin
    Memo1.Lines.Add('$' + IntToHex(LArrBytes[LIndex], 2));
  end;

  Memo1.Lines.Add('SizeOf : '+ IntToStr(SizeOf(LArrBytes)));
  Memo1.Lines.Add('Length : '+ IntToStr(Length(LArrBytes)));
end;

//=============================================================================
//  バイト配列の初期化(全ての要素を 0にする)
//  静的配列の場合
//  ZeroMemory手続きを使用する例
//
//  静的配列の場合は SizeOf 関数でバイト数を取得できる
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  LArrBytes : array [0..9] of Byte;
  LIndex    : Integer;
begin
  Memo1.Lines.Clear;

  // 初期化確認用に要素に値をセット
  for LIndex := Low(LArrBytes) to High(LArrBytes) do begin
    LArrBytes[LIndex] := Byte(LIndex + 1);
  end;

  // 配列の要素を初期化(全て0になる)
  ZeroMemory(@LArrBytes[0], SizeOf(LArrBytes));

  // 初期化後の各要素の値を確認表示
  for LIndex := Low(LArrBytes) to High(LArrBytes) do begin
    Memo1.Lines.Add('$' + IntToHex(LArrBytes[LIndex], 2));
  end;

  Memo1.Lines.Add('SizeOf : '+ IntToStr(SizeOf(LArrBytes)));
  Memo1.Lines.Add('Length : '+ IntToStr(Length(LArrBytes)));
end;




10_バイト列 ( PByte 型 ) データの初期化


PByte 型のバイト列データも ZeroMemory 手続きを使用して初期化できます.この場合の初期化は,バイト列データの値を全て $00 にします.
FillMemory 手続きを使用すると,全てのバイト列のデータを特定のバイト値にできます.



図22
PByte 型のバイト列データ
  • これは初期化していない時の値
  • ローカル変数なので初期化されていない

図23
初期化した状態の PByte データ列の値
  • 各バイト値を全て $00 にした場合

リスト17
//=============================================================================
//  バイト列テータの初期化
//  GetMem 関数で領域を確保した場合は初期化されない
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LPByte     : PByte;
  LPByteDst  : PByte;
  LBytevalue : Byte;
  LSize      : Integer;
  LIndex     : Integer;
begin
  Memo1.Lines.Clear;
  Memo1.Lines.BeginUpdate;

  //バイト列データ用のメモリ領域を確保
  LSize  := 100;
  GetMem(LPByte, LSize);
  try
    //確認表示
    //バイト列データを順番に取り出して表示
    LPByteDst := LPByte;
    for LIndex := 0 to LSize - 1 do begin
      LBytevalue :=  Byte(LPByteDst^);
      Memo1.Lines.Add('$' + IntToHex(LBytevalue, 2));

      //バイト列のポインタをインクリメント
      inc(LPByteDst);
    end;
  finally
    FreeMem(LPByte);
  end;
  Memo1.Lines.EndUpdate;
end;

//=============================================================================
//  バイト列テータの初期化
//  GetMem 関数で領域を確保した場合は初期化されない
//  ZeroMemory 手続きでバイト列データを 0 に初期化する例
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LPByte     : PByte;
  LPByteDst  : PByte;
  LBytevalue : Byte;
  LSize      : Integer;
  LIndex     : Integer;
begin
  Memo1.Lines.Clear;
  Memo1.Lines.BeginUpdate;

  //バイト列データ用のメモリ領域を確保
  LSize  := 100;
  GetMem(LPByte, LSize);
  try
    // バイト列のデータを初期化(全て0になる)
    ZeroMemory(LPByte, LSize);

    //確認表示
    //バイト列データを順番に取り出して表示
    LPByteDst := LPByte;
    for LIndex := 0 to LSize - 1 do begin
      LBytevalue :=  Byte(LPByteDst^);
      Memo1.Lines.Add('$' + IntToHex(LBytevalue, 2));

      //バイト列のポインタをインクリメント
      inc(LPByteDst);
    end;
  finally
    FreeMem(LPByte);
  end;
  Memo1.Lines.EndUpdate;
end;


上のサンプルではバイト列データ用のメモリ領域の確保に GetMem 関数を使用しています.
次のように,メモリの確保に AllocMem 関数を使用すると,確保したメモリ領域を 0 に自動で初期化してくれます.



図24
AllocMem 関数でメモリ領域を確保した場合
  • 確保したメモリ領域を 0 に初期化してくれる

リスト18
//=============================================================================
//  バイト列テータの初期化
//  AllocMem 関数で領域を確保した場合は 0 に初期化される
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LPByte     : PByte;
  LPByteDst  : PByte;
  LBytevalue : Byte;
  LSize      : Integer;
  LIndex     : Integer;
begin
  Memo1.Lines.Clear;
  Memo1.Lines.BeginUpdate;

  //バイト列データ用のメモリ領域を確保
  LSize  := 100;
  LPByte := AllocMem(LSize);
  try
    //確認表示
    //バイト列データを順番に取り出して表示
    LPByteDst := LPByte;
    for LIndex := 0 to LSize - 1 do begin
      LBytevalue :=  Byte(LPByteDst^);
      Memo1.Lines.Add('$' + IntToHex(LBytevalue, 2));

      //バイト列のポインタをインクリメント
      inc(LPByteDst);
    end;
  finally
    FreeMem(LPByte);
  end;
  Memo1.Lines.EndUpdate;
end;




11_Char 型の文字配列要素の初期化


Char 型の文字配列の要素も ZeroMemory 手続きを使用して初期化できますが,Char 型の文字配列の場合は専用の FillChar という手続きがあります.
静的な Char 型の文字配列で FillChar 手続きを使用する場合,第 2 引数に必要なバイト数は SizeOf 関数で取得できます.

動的な Char 型の文字配列が使用しているバイト数は,Length(配列の変数名) * SizeOf(Char) という計算式で取得できます.
動的な Char 型文字配列の場合,SizeOf 関数で取得した値は,配列の型のサイズになります.動的配列の変数はポインタですから,これはポインタのサイズです.したがって,32 ビットの EXE では 4, 64 ビットの EXE てば 8 になります.

FillChar 手続きの最後の 3 番目の引数は 1 バイトイトの整数または AnsiString 型の半角文字 (ASCII 文字) です.2 バイトの値を渡しても,実際に使用されるのは下位バイトだけです.

Char型の動的配列は,SetLength 関数で初期化されます.SetLength 手続きでサイズを拡張した場合,拡張前の要素のデータはそのまま残ります.拡張した部分は初期化状態となります.
改めて初期化する時に FillChar 手続きが使用できます.



図25
Char 型の動的配列要素の初期化例
  • SizeOf 関数で取得した値は 4 となる

リスト19
//=============================================================================
//  Char型の文字配列の初期化(全ての要素を Null 文字にする)
//  Char型の静的配列の場合
//  FillChar手続きを使用する例
//
//  FillChar 手続きの第 2 引数はバイト数
//  静的配列の場合は SizeOf 関数でバイト数を取得できる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LArrChar  : array [0..9] of Char;
  LIndex  : Integer;
begin
  Memo1.Lines.Clear;

  // 初期化確認用に要素に値をセット
  for LIndex := Low(LArrChar) to High(LArrChar) do begin
    LArrChar[LIndex] := Char((LIndex * 2) + $3042);
  end;
  Memo1.Lines.Add(LArrChar);


  // 初期化(全て Null 文字になる)
  FillChar(LArrChar[0], SizeOf(LArrChar), #0);

  // 初期化後の各要素の値を確認表示
  for LIndex := Low(LArrChar) to High(LArrChar) do begin
    Memo1.Lines.Add('$' + IntToHex(Ord(LArrChar[LIndex]), 4));
  end;

  Memo1.Lines.Add('SizeOf : '+ IntToStr(SizeOf(LArrChar)));
  Memo1.Lines.Add('Length * 2 : '+ IntToStr(Length(LArrChar) * SizeOf(Char)));
end;

//=============================================================================
//  Char型の文字配列の初期化(全ての要素を Null 文字にする)
//  Char型の静的配列の場合
//  ZeroMemory手続きを使用する例
//
//  ZeroMemory手続きの引数にはバイト数が必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LArrChar : array [0..9] of Char;
  LIndex   : Integer;
begin
  Memo1.Lines.Clear;

  // 初期化確認用に要素に値をセット
  for LIndex := Low(LArrChar) to High(LArrChar) do begin
    LArrChar[LIndex] := Char((LIndex * 2) + $3042);
  end;
  Memo1.Lines.Add(LArrChar);


  // 初期化(全て Null 文字になる)
  ZeroMemory(@LArrChar[0], Length(LArrChar) * SizeOf(Char));

  // 初期化後の各要素の値を確認表示
  for LIndex := Low(LArrChar) to High(LArrChar) do begin
    Memo1.Lines.Add('$' + IntToHex(Ord(LArrChar[LIndex]), 4));
  end;

  Memo1.Lines.Add('SizeOf : '+ IntToStr(SizeOf(LArrChar)));
  Memo1.Lines.Add('Length * 2 : '+ IntToStr(Length(LArrChar) * SizeOf(Char)));
end;

//=============================================================================
//  Char型の文字配列の初期化(全ての要素を Null 文字にする)
//  Char型の静的配列の場合
//  ZeroMemory手続きを使用する例
//
//  ZeroMemory手続きの引数にはバイト数が必要
//  静的配列ならば SizeOf 関数でバイト数が取得できる
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  LArrChar : array [0..9] of Char;
  LIndex   : Integer;
begin
  Memo1.Lines.Clear;

  // 初期化確認用に要素に値をセット
  for LIndex := Low(LArrChar) to High(LArrChar) do begin
    LArrChar[LIndex] := Char((LIndex * 2) + $3042);
  end;
  Memo1.Lines.Add(LArrChar);


  // 初期化(全て Null 文字になる)
  ZeroMemory(@LArrChar[0], SizeOf(LArrChar));

  // 初期化後の各要素の値を確認表示
  for LIndex := Low(LArrChar) to High(LArrChar) do begin
    Memo1.Lines.Add('$' + IntToHex(Ord(LArrChar[LIndex]), 4));
  end;

  Memo1.Lines.Add('SizeOf : '+ IntToStr(SizeOf(LArrChar)));
  Memo1.Lines.Add('Length * 2 : '+ IntToStr(Length(LArrChar) * SizeOf(Char)));
end;

//=============================================================================
//  Char型の文字配列の初期化(全ての要素を Null 文字にする)
//  Char型の動的配列の場合
//  FillChar手続きを使用する例
//
//  FillChar 手続きの第 2 引数はバイト数
//  動的配列静的の場合,SizeOf 関数で取得した値は型のサイズになる
//=============================================================================
procedure TForm1.Button4Click(Sender: TObject);
var
  LArrChar : array of Char;
  LText    : string;
  LIndex   : Integer;
begin
  Memo1.Lines.Clear;

  SetLength(LArrChar, 10);

  // 初期化確認用に要素に値をセット
  for LIndex := Low(LArrChar) to High(LArrChar) do begin
    LArrChar[LIndex] := Char((LIndex * 2) + $3042);
  end;
  LText := string(@LArrChar[0]);
  Memo1.Lines.Add(LText);


  // 初期化(全て Null 文字になる)
  FillChar(LArrChar[0], Length(LArrChar) * SizeOf(Char), #0);

  // 初期化後の各要素の値を確認表示
  for LIndex := Low(LArrChar) to High(LArrChar) do begin
    Memo1.Lines.Add('$' + IntToHex(Ord(LArrChar[LIndex]), 4));
  end;

  Memo1.Lines.Add('SizeOf : '+ IntToStr(SizeOf(LArrChar)));
  Memo1.Lines.Add('Length * 2 : '+ IntToStr(Length(LArrChar) * SizeOf(Char)));
end;

//=============================================================================
//  Char型の文字配列の初期化(全ての要素を Null 文字にする)
//  Char型の動的配列の場合
//  ZeroMemory手続きを使用する例
//
//  ZeroMemory手続きの引数にはバイト数が必要
//  動的配列静的の場合,SizeOf 関数で取得した値は型のサイズになる
//=============================================================================
procedure TForm1.Button5Click(Sender: TObject);
var
  LArrChar : array of Char;
  LText    : string;
  LIndex   : Integer;
begin
  Memo1.Lines.Clear;

  SetLength(LArrChar, 10);

  // 初期化確認用に要素に値をセット
  for LIndex := Low(LArrChar) to High(LArrChar) do begin
    LArrChar[LIndex] := Char((LIndex * 2) + $3042);
  end;
  LText := string(@LArrChar[0]);
  Memo1.Lines.Add(LText);


  // 初期化(全て Null 文字になる)
  ZeroMemory(@LArrChar[0], Length(LArrChar) * SizeOf(Char));

  // 初期化後の各要素の値を確認表示
  for LIndex := Low(LArrChar) to High(LArrChar) do begin
    Memo1.Lines.Add('$' + IntToHex(Ord(LArrChar[LIndex]), 4));
  end;

  Memo1.Lines.Add('SizeOf : '+ IntToStr(SizeOf(LArrChar)));
  Memo1.Lines.Add('Length * 2 : '+ IntToStr(Length(LArrChar) * SizeOf(Char)));
end;




12_レコード型の変数の初期値


レコード型の変数の初期値についても同じです.
グローバルなレコード型の変数はデフォルト値で初期化されます.初期化の値は,String 型の文字列では長さ 0 の空文字で,数値では 0 です.ローカル変数のレコード型の変数は初期化されません.ただし,String 型のメンバーの値は,単独の String 型の変数と同じです.グローバル変数もローカル変数も長さ 0 の空文字で初期化されます.
以下は,これらのことを確認するためのテストコードです.下のコードは,レコード型の変数がグロバール変数の場合です.



図26
EXE 実行開始時の画面
  • グローバル変数は初期化されている
図27
レコード型の変数の各メンバーに値をセット

リスト20
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TSamleInfoRec = record
    Text     : string;
    Int32    : Integer;
    Float    : Double;
    CharArry : array [0..9] of Char;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    FSampleInfo : TSamleInfoRec;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  グローバルなレコード型の変数のメンバの値を表示
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;

  Memo1.Lines.Add(FSampleInfo.Text);
  Memo1.Lines.Add(IntToStr(FSampleInfo.Int32));
  Memo1.Lines.Add(FormatFloat('0.000', FSampleInfo.Float));
  Memo1.Lines.Add(FSampleInfo.CharArry);
end;

//=============================================================================
//  レコード型のメンバの値を設定
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Clear;

  FSampleInfo.Text     := '日本語 ABC 文字列';
  FSampleInfo.Int32    := 5432;
  FSampleInfo.Float    := 123.456;
  StrPCopy(FSampleInfo.CharArry, 'Char 型文字配列');

  Memo1.Lines.Add(FSampleInfo.Text);
  Memo1.Lines.Add(IntToStr(FSampleInfo.Int32));
  Memo1.Lines.Add(FormatFloat('0.000', FSampleInfo.Float));
  Memo1.Lines.Add(FSampleInfo.CharArry);
end;

end.


以下のコードは,レコード型の変数がローカル変数の場合です.



図28
ローカル変数は初期化されない

リスト21
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TSamleInfoRec = record
    Text     : string;
    Int32    : Integer;
    Float    : Double;
    CharArry : array [0..19] of Char;
  end;

  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  ローカルなレコード型の変数はは初期化されない
//  ただし,String型の文字列はグローバルでもローカル変数でも長さ0の空文字となる
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LSampleInfo : TSamleInfoRec;
begin
  Memo1.Lines.Clear;

  Memo1.Lines.Add(LSampleInfo.Text);
  Memo1.Lines.Add(IntToStr(LSampleInfo.Int32));
  Memo1.Lines.Add(FloatToStr(LSampleInfo.Float));
  Memo1.Lines.Add(FormatFloat('0.000', LSampleInfo.Float));
  Memo1.Lines.Add(LSampleInfo.CharArry);
end;

end.


レコード型の変数も,型付きの静的配列と同じように,クラスのメンバーではないグローバル変数は各メンバーの初期値を設定できます.その例です.



図29
グローバル変数は初期値を設定できる
  • クラスのメンバの変数の場合は設定不可

リスト22
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TSamleInfoRec = record
    Text  : string;
    Int32 : Integer;
    Float : Double;
  end;

  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
var
  FSampleInfo : TSamleInfoRec = (Text:'文字列'; Int32:12345; Float:543.21);

//=============================================================================
//  レコード型変数の初期値を設定例
//  レコード型の変数がグローバルであれば初期値を設定できる
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;

  FSampleInfo.Text := '日本語 ' + FSampleInfo.Text;

  Memo1.Lines.Add(FSampleInfo.Text);
  Memo1.Lines.Add(IntToStr(FSampleInfo.Int32));
  Memo1.Lines.Add(FormatFloat('0.000', FSampleInfo.Float));
end;

end.


レコード型の変数も,型付きの静的配列と同じように,定数として使用する場合も,各メンバーの初期値を設定できます.その例です.



図30
定数として使用する場合は初期値を設定できる

リスト23
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TSamleInfoRec = record
    Text  : string;
    Int32 : Integer;
    Float : Double;
  end;

  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  定数値としてのレコード型の変数
//  定数値なのでメンバの値は変更できない
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
const
  LSampleInfo : TSamleInfoRec = (Text:'文字列'; Int32:12345; Float:543.21);
begin
  Memo1.Lines.Clear;

  Memo1.Lines.Add(LSampleInfo.Text);
  Memo1.Lines.Add(IntToStr(LSampleInfo.Int32));
  Memo1.Lines.Add(FormatFloat('0.000', LSampleInfo.Float));
end;

end.




13_標準関数 Default を使用する初期化


標準関数の Default 関数を使用すると,配列とレコード型の変数を初期化できます.ただし,配列は型宣言された変数に限ります.

初期値を設定すること,つまり,配列の要素あるいはレコード型のメンバの値を特定の値にする場合も初期化ということがありますが,Default 関数による初期化は,変数のデフォルト値にすることを意味します.デフォルトの値とは,String 型では空文字,Char 型は Null 文字,数値の場合は 0 です. ポインタ型とオブジェクト型の場合は nil がデフォルトの初期値です.

Default 関数は,オンラインヘルプでは以下のページにしか記述がありません.おそらく,アンドキュメントな関数と言ってもいいかも知れません.






14_標準関数 Default を使用して型宣言の静的配列を初期化


標準関数 Default を使用して型宣言の Char 型の静的な文字配列を初期化する例です.
Char 型の静的な文字配列の場合,初期化しないと,ゴミが表示されますが,Default 関数で初期化すれば全ての要素が Null 文字になります.
Char 型の静的な文字配列は,使用するメモリ領域が固定です.したがって,FillChar 手続きでも初期化できます.FillChar 手続きは,型宣言なしの Char 型の静的な文字配列も初期化できます.



図31
型宣言の静的配列の初期化
  • 初期化の処理がない場合
図32
型宣言の静的配列の初期化
  • Default 関数で初期化した場合

リスト24
type
  TArrayChar = array [0..4] of Char;

//=============================================================================
//  静的配列の初期値 (型宣言の Char 型の静的配列)
//  初期化処理がない場合
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LCharArry : TArrayChar;
  LIndex    : Integer;
begin
  Memo1.Lines.Clear;

  for LIndex := 0 to High(LCharArry) do begin
    Memo1.Lines.Add(IntToStr(LIndex) + ' : ' + LCharArry[LIndex]);
  end;
end;

//=============================================================================
//  静的配列の初期値 (型宣言の Char 型の静的配列)
//  Default 関数で初期化した場合
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LCharArry : TArrayChar;
  LIndex    : Integer;
begin
  Memo1.Lines.Clear;

  LCharArry := System.Default(TArrayChar);

  for LIndex := 0 to High(LCharArry) do begin
    Memo1.Lines.Add(IntToStr(LIndex) + ' : ' + LCharArry[LIndex]);
  end;
end;




15_標準関数 Default を使用して型宣言の動的配列を初期化


標準関数 Default を使用して型宣言の動的な整数型の配列を初期化する例です.
このテストでは SetLength 手続きで配列の領域 (要素数) を設定しています.したがって,配列の各要素の値はデフォルトの 0 に初期化されます.
動的配列を Default 関数で初期化すると,要素の値が初期化されるのではなく,配列そのものが初期化されて,要素数は 0 となります.



図33
型宣言の動的配列の初期化
  • 初期化の処理がない場合
  • SetLength 関数で領域 (要素数) を確保しているので 0 に初期化される
図34
型宣言の動的配列の初期化
  • Default 関数で初期化した場合
  • 配列要素ではなく,配列が初期化されるので,要素の数が 0 になる

リスト25
uses
  System.Types;

{$R *.dfm}

//=============================================================================
//  動的配列の初期値 (型宣言の整数型の動的配列)
//  初期化処理がない場合
//
//  動的配列領域 (要素数) を SetLength 手続きで割り当てた場合
//  その領域 (要素) は 0 または nil に設定される
//
//  TIntegerDynArray の使用には uses に Types が必要
//===========================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LArrayInt : TIntegerDynArray;
  LIndex    : Integer;
begin
  Memo1.Lines.Clear;

  SetLength(LArrayInt, 4);

  for LIndex := 0 to High(LArrayInt) do begin
    Memo1.Lines.Add(IntToStr(LIndex) + ' : ' + IntToStr(LArrayInt[LIndex]));
  end;
end;

//=============================================================================
//  動的配列の初期値 (型宣言の整数型の動的配列)
//  Default 関数で初期化した場合
//  領域 (要素数) は 0 となる
//
//  TIntegerDynArray の使用には uses に Types が必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LArrayInt : TIntegerDynArray;
begin
  Memo1.Lines.Clear;

  SetLength(LArrayInt, 4);

  LArrayInt := System.Default(TIntegerDynArray);

  Memo1.Lines.Add('要素数 : ' + IntToStr(Length(LArrayInt)));
end;




16_標準関数 Default を使用してレコード型を初期化


標準関数 Default を使用してレコード型を初期化する例です.レコード型の初期化は,レコード型の各メンバの値をデフォルトの初期値に設定することを意味します.
初期化しない場合はかなり文字化けしていますが,この状態はその時のメモリの状態にもよります.下図は IDE 上で実行した結果ですが,この程度の単純なプログラムであれば,EXE を直接実行すれば文字化けはほとんど発生しません.

String 型の変数は,グローバルな変数であっても,ローカルな変数でも,レコード型のメンバであっても空文字に初期化されます.

レコード型の変数の初期化に FillChar 手続きも使用できますが,レコードのメンバに String 型等,可変長の変数があると問題が発生します.
FillChar 手続きは,指定バイト数のメモリの値を特定の値 にする関数です.
PChar 型も任意の文字数を格納できますが,PChar はポインタ型です.ポインタ型の変数が示すアドレスは,32 ビットのアプリでは 4 バイト,64 ビットのアプリでは 8 バイトの固定長です.



図35
レコード型の初期化
  • 初期化の処理がない場合
  • 結果はその時のメモリの状態による
図36
レコード型の初期化
  • Default 関数で初期化した場合
図37
再び [Button1] をクリックした結果
  • 初期化の操作によってメモリの状態が変化している
  • 結果はその時のメモリの状態による

リスト26
type
  TSamleInfoRec = record
    Text     : string;
    Int32    : Integer;
    Float    : Double;
    CharArry : array [0..9] of Char;
  end;

//=============================================================================
//  レコード型の初期値
//  String 型はグローバルでもローカルでも空文字に初期化される
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LSampleInfo : TSamleInfoRec;
begin
  Memo1.Lines.Clear;

  Memo1.Lines.Add('Text     : ' + LSampleInfo.Text);
  Memo1.Lines.Add('Int32    : ' + IntToStr(LSampleInfo.Int32));
  Memo1.Lines.Add('Float    : ' + FloatToStr(LSampleInfo.Float));
  Memo1.Lines.Add('Float    : ' + FormatFloat('0.000', LSampleInfo.Float));
  Memo1.Lines.Add('CharArry : ' + LSampleInfo.CharArry);
end;

//=============================================================================
//  レコード型の初期化
//  Default 関数で初期化した場合
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LSampleInfo : TSamleInfoRec;
begin
  Memo1.Lines.Clear;

  LSampleInfo := System.Default(TSamleInfoRec);

  Memo1.Lines.Add('Text     : ' + LSampleInfo.Text);
  Memo1.Lines.Add('Int32    : ' + IntToStr(LSampleInfo.Int32));
  Memo1.Lines.Add('Float    : ' + FloatToStr(LSampleInfo.Float));
  Memo1.Lines.Add('Float    : ' + FormatFloat('0.000', LSampleInfo.Float));
  Memo1.Lines.Add('CharArry : ' + LSampleInfo.CharArry);
end;