Delphi Programming / Object Pascal
[掲載 2014年02月17日] [更新 2019年04月30日] Delphi 一般・その他
変数やオブジェクトの初期値
動作確認等
Windows 7 U64(SP1) + Delphi XE(UP1) Pro
変数の初期値には注意が必要です。
グローバル変数は、ポイント型とオブジェクト型の場合、nil に初期化されます。数値は 0 に初期化されます。1 文字の型である Char 型の変数は Null 文字に初期化されます。一方、イベントやメソッド内で定義したそれらのローカル変数は初期化されません。
string 型の文字列変数は、グローバル変数もローカル変数も長さ 0 の空文字となります。
下図はクラス変数の場合です。クラス変数もグローバル変数ですから初期化されます。
図1
クラス型変数の初期値
copy code
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
ローカルな整数型の変数の、初期化されていない値の例
copy code
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
生成されていないオブジェクトを操作すると例外が発生する
copy code
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 ;
通常は、上のコードをコンパイルすると、次のような警告が表示されます。
オブジェクトのインスタンスを生成するコードが存在する場合、この表示が現れるかどうかは、オブジェクトのインスタンスを生成するコードを書く位置にもよります。
[DCC 警告] Unit1.pas(63): W1036 変数 'aBtn' が初期化されていない可能性があります
次のコードも「初期化されていない可能性があります」の警告が表示されます。
ローカル変数は初期化されません。このコードでは LIntB に値が代入されない場合があります。したがって、LIntC の値も不定値になってしまうことがあります。これを避けるには、LIntB に何らかの初期値を代入しておきます。あるいは、条件分岐に else を追加して LIntB に、必ず値がセットされるようにします。
上のコードもこのコードも、短いコードですから、すぐに判断できますが、実際のアプリ開発でこのようなコーディングをしてしまうと、予期しない結果となる可能性があります。
[DCC 警告] Unit1.pas(37): W1036 変数 'LIntB' が初期化されていない可能性があります
copy code
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' に代入された値は使われていません
String 型の文字列変数は、グローバル変数もローカル変数も長さ 0 の空文字となります。
問題は文字列の領域を確保したり長さを設定したりする場合です。Windwos API
の関数類を使用する際には必要となることがあります。
領域を確保しただけとか、長さを設定しただけだと、いわゆる「ゴミ」が入ることがあります。これはメモリ上の不定な領域の値なので、いつも同じ値とは限りません。また、全く入らないか、制御文字等の場合は表示されません。
[備考 1]
文字列やテキストを扱う Windows API の関数類では、引数の値の設定によって、必要なバッファのサイズ (バイト数または文字数) が取得できることがあります。
そのバッファのサイズで文字列の長さを設定してから、実際にその Windows API で目的の文字列等を扱ったり取得ができます。、
[備考 2]
結果の文字列の「ゴミ」は、下に示すコードの実行結果の場合です。実際に「ゴミ」が入るかどうかは、領域を確保した後にどんな処理をするかにもよります。
SetLength
手続きで String 型の文字列を格納するメモリ領域を確保する場合です。
SetLength 手続きは確保したメモリ領域を初期化しません。FillChar 手続きを使用すると初期化できます。FillChar 手続きの第 1 引数には String 型の文字列の最初の文字を指定します。文字のインデックスを指定しないで変数を渡すと、String 型の変数として機能しなくなります。
図5
SetLength で String 型の変数用のメモリを確保
図6
SetLength で String 型の変数用のメモリを確保
copy code
// =============================================================================
// 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 関数を使用した場合
確保したメモリが初期化される
copy code
// =============================================================================
// 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-} を指定します。これがデフォルトのコンパイラ指令となっています。
copy code
// 通常の定数(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
下のコードの実行結果
copy code
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 回以上クリックした結果
copy code
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
ボタンをクリックすると状態が変わる
copy code
// =============================================================================
// フォーム生成時の処理
// =============================================================================
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
クラスのメンバでない変数は初期化できる
copy code
implementation
{$R *.dfm}
var
FValue : Integer = 100 ;
// =============================================================================
// クラスのメンバでないグローバルな変数の操作
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
FValue := FValue + 300 ;
MessageBox(Handle, PChar(IntToStr(FValue)), '結果' , MB_ICONINFORMATION);
end ;
Char 方の文字配列は、上のサンプルでも使用している FillChar 手続きで初期化できます・
一般的に、配列の要素の値は、for next 等のループで初期化できますが、要素の値を全て 0 に初期化するのであれば ZeroMemory 手続きが利用できます。
ZeroMemory 手続きによる初期化は、静的配列でも動的配列でも使用できます。
ZeroMemory の第 2 引数には、その配列が使用しているバイト数を指定します。そのバイト数には、配列の要素数に、変数の型のバイトサイズを乗算した値を使用します。配列の要素数は Length 関数で取得できます。また、変数の型のバイトサイズは SizeOf 関数で取得できます。
図16
整数型の静的配列の要素を全て 0 にする
copy code
// =============================================================================
// 整数型の静的配列の値を全て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
型付き定数で定義した配列の要素の値を取得
copy code
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 .
動的配列は、SetLength 手続きで要素数を確保するとデフォルトの値に初期化されます。ただし、それは初回だけです。2 回目以降の挙動についてはオンラインヘルプで確認してください。
型宣言の動的配列であれば、InitializeArray 関数を使用して、その要素の値を初期化できます。ただし、値の指定はありません。デフォルトの初期値である 0 となります。上の静的配列の初期化のサンプルで使用した ZeroMemory 手続きでも 0 に初期化できます。
下に示すコードは、TIntegerDynArray 型の整数配列の各要素の値を全て 0 にする例です。
図19
動的配列の要素の初期化例
各要素に値を代入した後、初期化したので全ての要素の値が 0 になっている
copy code
// =============================================================================
// 配列要素の初期化
// 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 となる
copy code
// =============================================================================
// 動的に割り当てた変数の初期化(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
バイト型配列の要素の初期化
copy code
// =============================================================================
// バイト配列の初期化(全ての要素を 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 データ列の値
copy code
// =============================================================================
// バイト列テータの初期化
// 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 関数でメモリ領域を確保した場合
copy code
// =============================================================================
// バイト列テータの初期化
// 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 ;
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 型の動的配列要素の初期化例
copy code
// =============================================================================
// 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 ;
レコード型の変数の初期値についても同じです。
グローバルなレコード型の変数はデフォルト値で初期化されます。初期化の値は、String 型の文字列では長さ 0 の空文字で、数値では 0 です。ローカル変数のレコード型の変数は初期化されません。ただし、String 型のメンバーの値は、単独の String 型の変数と同じです。グローバル変数もローカル変数も長さ 0 の空文字で初期化されます。
以下は、これらのことを確認するためのテストコードです。下のコードは、レコード型の変数がグロバール変数の場合です。
図26
EXE 実行開始時の画面
図27
レコード型の変数の各メンバーに値をセット
copy code
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
ローカル変数は初期化されない
copy code
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
グローバル変数は初期値を設定できる
copy code
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
定数として使用する場合は初期値を設定できる
copy code
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 .
標準関数の Default 関数を使用すると、配列とレコード型の変数を初期化できます。ただし、配列は型宣言された変数に限ります。
初期値を設定すること、つまり、配列の要素あるいはレコード型のメンバの値を特定の値にする場合も初期化ということがありますが、Default 関数による初期化は、変数のデフォルト値にすることを意味します。デフォルトの値とは、String 型では空文字、Char 型は Null 文字、数値の場合は 0 です。
ポインタ型とオブジェクト型の場合は nil がデフォルトの初期値です。
Default 関数は、オンラインヘルプでは以下のページにしか記述がありません。おそらく、アンドキュメントな関数と言ってもいいかも知れません。
14_ 標準関数 Default を使用して型宣言の静的配列を初期化
標準関数 Default を使用して型宣言の Char 型の静的な文字配列を初期化する例です。
Char 型の静的な文字配列の場合、初期化しないと、ゴミが表示されますが、Default 関数で初期化すれば全ての要素が Null 文字になります。
Char 型の静的な文字配列は、使用するメモリ領域が固定です。したがって、FillChar 手続きでも初期化できます。FillChar 手続きは、型宣言なしの Char 型の静的な文字配列も初期化できます。
図31
型宣言の静的配列の初期化
図32
型宣言の静的配列の初期化
copy code
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 になる
copy code
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
レコード型の初期化
図37
再び [Button1] をクリックした結果
初期化の操作によってメモリの状態が変化している
結果はその時のメモリの状態による
copy code
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 ;