手続きと関数
Object Pascalにおいて、手続き(プロシージャ)とは戻り値のないサブプログラム、つまりVBでいうSubプロシージャ、C/C++のvoid型関数のことを言い、関数とは戻り値のあるサブプログラム、つまりVBでいうFunctionプロシージャのことを言います。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
// 名前に応じたメッセージを作成する関数
function CreateMessage( name: string ) : string;
begin
result := 'Hello, ' + name + '.';
end;
// 名前に応じてメッセージを表示するプロシージャ
procedure OutputMessage( name: string );
begin
Writeln( CreateMessage( name ) );
end;
// メインプログラム
begin
// メッセージを表示
OutputMessage( 'santa marta' );
OutputMessage( 'Guest' );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
Hello, santa marta. Hello, Guest. Press any key to continue
まず、全てのサブプログラムはメインプログラムの前に記述されている必要があります。 それ以外の部分、戻り値の型指定、パラメータの指定方法などは問題ないと思います。 ただ、関数で戻り値を返す場合は、暗黙の変数resultに戻り値を代入するため、returnなどは使用しません。 また、VBと同じように関数名に値を代入することで関数の戻り値とする事もできます。
このプログラムでは、メインプログラムからOutputMessageプロシージャを呼び出し、さらにそのOutputMessage プロシージャはCreateMessage関数を呼び出しています。 プロシージャ・関数と名称こそ異なれど、その概念は他の言語と変わりないと言えます。
ローカル変数とスコープ
サブプログラムの中でローカル変数を宣言、使用できます。 サブプログラム宣言の直後にvar文で変数を宣言します。 使用の際は他の変数と全く同じです。 また、スコープの概念も他の言語と同じで、サブプログラム内で宣言された変数はそのサブプログラムの中においてのみ有効です。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
var
value: integer;
// ローカル変数valueの値を変更し、表示するプロシージャ
procedure SetNewValue( newValue: integer );
var
value: integer;
begin
value := newValue;
Writeln( value );
end;
// 変数valueの値を表示するプロシージャ
procedure OutputValue();
begin
Writeln( value );
end;
// メインプログラム
begin
value := 3;
OutputValue;
SetNewValue( 5 );
OutputValue;
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
3 5 3 Press any key to continue
このように、ローカル変数と同じ名前の変数がメインプログラムで宣言されていても、明確に区別されます。
参照渡し、値渡し、定数パラメータ
Object Pascalのサブプログラムの引数は、VB.NET、C#、C/C++などと同様に既定で値渡しです。 参照渡しにする場合は var キーワードを付加します。 また、パラメータを定数としてサブプログラム内での変更を許可しない場合はconstをつけます。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
var
intValue: integer;
// 参照渡し
procedure CallByReference( var value: integer );
begin
value := value + 1;
end;
// 値渡し
procedure CallByValue( value: integer );
begin
value := value + 1;
end;
// 定数パラメータ
procedure ConstantParameter( const value: integer );
begin
// エラー: 代入できない左辺値です
// value := value + 1;
end;
// 現在の値を表示するプロシージャ
procedure OutputValue;
begin
Writeln( 'intValue = ', intValue );
end;
// メインプログラム
begin
intValue := 15;
OutputValue;
CallByReference( intValue );
OutputValue;
CallByValue( intValue );
OutputValue;
ConstantParameter( intValue );
OutputValue;
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
intValue = 15 intValue = 16 intValue = 16 intValue = 16 Press any key to continue
実行結果のとおり、値渡しで渡されたパラメータの値は、サブプログラム内で変更することができます。 また、定数パラメータに対して値を代入しようとするコードは、コンパイル時にエラーとなります。
定数
定数はconst文で宣言します。 Delphiでは他の言語同様、定数の名前は全て大文字にすることが多いようです。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
const
CONSTANT_VALUE = 5;
ENDOFPROGRAM_MESSAGE = 'Press any key to continue';
var
variableValue: integer;
begin
variableValue := CONSTANT_VALUE;
Writeln( 'variableValue = ', CONSTANT_VALUE );
// 終了メッセージを表示
Write( ENDOFPROGRAM_MESSAGE );
Readln;
end.
variableValue = 5 Press any key to continue
また、当然ですが、定数への値の代入は許可されません。
列挙型
列挙型の概念も他の言語と変わりませんが、その動作は多少異なります。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
type
Musumes = ( Aibon = 0,
Nono,
Rikacchi,
Konkon,
Marippe );
var
intValue: integer;
musume: Musumes;
musumeName: array[Musumes] of string = ('加護亜依',
'辻希美',
'石川梨華',
'紺野あさ美',
'矢口真里' );
begin
// 'Integer' と 'Musumes' には互換性がありません
// intValue := Aibon;
// 'Musumes' と 'Integer' には互換性がありません
// musume := 3;
// 列挙型の値の代入
musume := Rikacchi;
// 各列挙型メンバの値
Writeln( 'Order of Aibon: ', Ord(Aibon) );
Writeln( 'Order of Marippe: ', Ord(Marippe) );
Writeln( 'Order of musume: ', Ord(musume) );
Writeln;
// 列挙型の使用方法
Writeln( musumeName[Musumes(0)] );
Writeln( musumeName[Nono] );
Writeln( musumeName[musume] );
Writeln;
musume := Musumes(4);
// 現在のmusumeの値
Writeln( 'musume = ', Ord(musume) );
// musumeの値をディクリメント
Dec(musume);
Write( musumeName[musume] ); Writeln( ', musume = ', Ord(musume) );
// musumeの値をインクリメント
Inc(musume);
Write( musumeName[musume] ); Writeln( ', musume = ', Ord(musume) );
// Nonoの一つ前の値を取得
Writeln( musumeName[Pred(Nono)] );
// Nonoの一つ前の、一つ後の値を取得
Writeln( musumeName[Succ(Pred(Nono))] );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
Order of Aibon: 0 Order of Marippe: 4 Order of musume: 2 加護亜依 辻希美 石川梨華 musume = 4 紺野あさ美, musume = 3 矢口真里, musume = 4 加護亜依 辻希美 Press any key to continue
この結果の通り、他の言語とは異なり列挙型はその他の数値型と互換性がないというのが最大の特徴といえます。 その他の宣言、使用法などはほとんど同じです。 ただ、直接数値型として扱うことができないので、インクリメント・ディクリメントなどを行うサポート関数がいくつか存在します。
文字列型配列の宣言時、添え字の部分に直接列挙型を指定していますが、こうすることにより、配列の上限と下限が自動的に列挙型の上限と下限に指定されます。 しかし、こうするとIntegerなどの整数値で添え字を指定することができなくなります。 また、整数値で添え字の範囲を指定して配列を宣言すると、添え字に列挙型を直接指定する事はできなくなります。
文字列操作
Object Pascalでの文字列の動作は、.NET Frameworkの文字列型と非常に似た動作をします。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
var
s1, s2, s3: string;
s : string;
i, l : integer;
begin
s1 := 'モー';
s2 := 'ニング';
s3 := '娘。';
// 連結
s := s1 + s3;
Write( s, 'は' );
// 挿入 (s2をsの5バイト目に)
Insert( s2, s, 5 );
Writeln( s, 'の略です。' );
// コピー
s1 := Copy( s, 0, Length(s) );
// 削除 ( sの5バイト目からs2の長さ分を )
Delete( s, 5, Length(s2) );
Writeln( s1, 'は', s, 'と略されます。' );
// 代入
s := s1;
// インデックスを取得
Writeln( '文字「', s3, '」は', s, 'の',
Pos( s3, s ), 'バイト目にあります。' );
// 空文字を代入
s3 := '';
// インデクサ的アクセス
i := 1;
l := Length(s);
while ( i + 1 <= l ) do
begin
s3 := s[i] + s[i+1];
Writeln( s3 );
i := i + 2;
end;
// 0番目の要素は参照できません
// - LengthまたはSetLengthを使って下さい
// Writeln( s[0] );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
モー娘。はモーニング娘。の略です。 モーニング娘。はモー娘。と略されます。 文字「娘。」はモーニング娘。の11バイト目にあります。 モ ー ニ ン グ 娘 。 Press any key to continue
このようにかなり柔軟な文字列操作を行うことができます。 Delete、Insert、Lengthなどがインスタンスメソッドではなくサポート関数として存在することを除いては、先程述べたようにほとんど.NET Frameworkの文字列型と同じといっていいと思います。 しかし、一つだけ違う点を上げるとすれば、文字列型に対する添え字の下限は0ではなく1ということです。 0番目の要素にアクセス使用とするとエラーになります。 これには深い意味があるようですが、それはこの次で考察します。
ShortString, AnsiString, WideString
stringとはAnsiStringのエイリアスです。 Object Pascalの文字列型にはShortString, AnsiString, WideStringの三種類があります。 また、先程述べたインデックス0の意味も調べてみます。 この例ではインデックス0を参照するために変数の値をインデックスに指定しますが、直接0を指定しようとするとエラーになります。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
var
ss: ShortString;
sa: AnsiString;
sw: WideString;
i : integer;
ls, la, lw: integer;
begin
// 10バイトの文字列を代入
ss := '0123456789';
sa := ss;
sw := sa;
// ss(ShortString)を一バイトずつ表示
Write( 'ss: ' );
ls := Length( ss );
for i := 1 to ls do
Write( ss[i] );
Writeln;
// sa(AnsiString)を一文字(一バイト)ずつ表示
Write( 'sa: ' );
la := Length( sa );
for i := 1 to la do
Write( sa[i] );
Writeln;
// sw(WideString)を一文字ずつ表示
Write( 'sw: ' );
lw := Length( sw );
for i := 1 to lw do
Write( sw[i] );
Writeln;
// 長さと0番目の要素を文字ではなく数値として表示
i := 0;
Writeln( 'ss[0] is ', Ord( ss[i] ), ', Length of ss is ', ls );
Writeln( 'sa[0] is ', Ord( sa[i] ), ', Length of sa is ', la );
Writeln( 'sw[0] is ', Ord( sw[i] ), ', Length of sw is ', lw );
// AnsiStringとWideStringの違い
sa := '全角文字';
sw := sa;
la := Length( sa );
lw := Length( sw );
Writeln( sa, ' Length: ', la );
Writeln( sw, ' Length: ', lw );
// sw(WideString)を一文字ずつ表示
for i := 1 to lw do
Writeln( sw[i] );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
ss: 0123456789 sa: 0123456789 sw: 0123456789 ss[0] is 10, Length of ss is 10 sa[0] is 0, Length of sa is 10 sw[0] is 0, Length of sw is 10 全角文字 Length: 8 全角文字 Length: 4 全 角 文 字 Press any key to continue
まず、三種類の文字列型の意味を説明すると、ShortStringは以前のPascalで用いられていた文字列型との互換性のために残された短い文字列型と呼ばれるもので、静的に256バイトが割り当てられ0バイト目(Object Pascalの用語では第一バイト)に文字列全体の長さが格納され、残りの255バイトに実際の文字列が格納されます。 これはC/C++などのnull で終わるchar型配列とは異なる文字列型の実装方法です。 しかし、実際に文字列を用いる場合は255バイトでは不足するおそれがあります。
そこで新たに用意されたのが、長い文字列と呼ばれるもので、これにはANSI文字を格納するAnsiStringとUnicode文字を扱うWideStringがあり、それぞれ2ギガ・バイトまでの文字列を扱うことができます。 これらの型は4バイトのメモリを占有するポインタ型で、文字列の終端にはヌルが付加されます。 先頭の4バイトには文字列の長さを保持するための2バイトと、残り2バイト分には参照カウンタが含まれます。
また、どの文字列型もインデックスは1から始まり、互換性の問題からShortStringのインデックス0が長さを表すのに対して、 AnsiStringとWideStringではインデックス0は意味を成しません。 また、これらの文字列型の一文字を表す型にChar, AnsiChar, WideCharがあります。 CharはAnsiCharと同義です。 実行結果から分かるとおり、WideString型の一つのインデックスの表す文字は2バイト(実際にはWideChar型)となります。 また、長さもバイト数ではなく文字数で返されます。
集合型 その1
集合型はC/C++, VBなどの言語にはない、Object Pascalの特徴的な型です。 その名の通り、ある要素の集合を扱います。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
type
// エラー: 集合型は256個以下の要素しかもてません
// IntegerValues = set of 0..1000;
// エラー: 集合型は256個以下の要素しかもてません
// IntegerValues = set of integer;
// Byte型の集合
// Byte型はちょうど0から255の256個
ByteValues = set of Byte;
// AからZの集合
LargeLetters = set of 'A'..'Z';
var
AToN : LargeLetters;
OToZ : LargeLetters;
Decades: ByteValues;
// AからNの集合に含まれるかをチェックするプロシージャ
procedure IsAToN( letter: Char );
begin
Write( letter, 'はAからNに' );
if letter in AToN then
Writeln( '含まれます' )
else
Writeln( '含まれません' );
end;
// OからZの集合に含まれるかをチェックするプロシージャ
procedure IsOToZ( letter: Char );
begin
Write( letter, 'はOからZに' );
if letter in OToZ then
Writeln( '含まれます' )
else
Writeln( '含まれません' );
end;
// 1から10の値かをチェックするプロシージャ
procedure IsDecades( value: Byte );
begin
Write( value, 'は1から10の値' );
if value in Decades then
Writeln( 'です' )
else
Writeln( 'ではありません' );
end;
// メインプログラム
begin
// AからNの大文字アルファベットを表す集合
AToN := ['A'..'N'];
// OからZの大文字アルファベットを表す集合
OToZ := ['O'..'Z'];
// 1から10までの整数の集合
Decades := [1..10];
// その値が集合に含まれるかチェック
IsAToN( 'K' );
IsOToZ( 'A' );
IsAToN( 'i' );
IsOToZ( 'r' );
IsDecades( 6 );
IsDecades( 0 );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
KはAからZに含まれます AはOからZに含まれません iはAからNに含まれません rはOからZに含まれません 6は1から10の値です 0は1から10の値ではありません Press any key to continue
まず、集合型を宣言する際の注意点として、集合の要素は256個を越えてはいけないと言うことです。 例えば、Integer型の値全てを扱うような集合は要素数が256を越えるので宣言できませんが、Byte型であれば0から255までの256個の値しか持ち得ないので、集合型として利用できます。 これは型から直接集合型を宣言する場合ですが、特定の値の範囲を用いて集合型を宣言することができます。 ただ、いずれの場合も「set of」で何の集合であるかを指定します。
また、宣言した集合型は、変数として宣言・使用されます。 宣言された集合型の変数に集合に含まれる値を指定します。 空集合を作る際には[]を代入します。 そして、ある集合の中に特定の要素が含まれているかを調べるには in 演算子を用います。 この演算子の結果はBoolean型ですが、一般的に考えて in 演算子はif文で用いることが多いでしょう。
この例では集合型の機能のうち、ほんの一部しか使っていません。 これ以外の機能はこれ以降で引き続き説明していきます。
集合型 その2
集合型ではその包括関係を調べることもできます。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
type
// byte型の集合
SetOfByte = set of byte;
var
AllValues: SetOfByte;
Values1: SetOfByte;
Values2: SetOfByte;
Values3: SetOfByte;
Values4: SetOfByte;
// メインプログラム
begin
// 1〜20までの数全体を表す集合
AllValues := [1..20];
// 素数
Values1 := [2, 3, 5, 7, 11, 13, 17, 19];
// 2の倍数
Values2 := [2, 4, 6, 8, 10, 12, 14, 16, 18, 20];
// 奇数
Values3 := [1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
// 4の倍数
Values4 := [4, 8, 12, 20];
Writeln( '素数は奇数の部分集合か ', Values1 >= Values3 );
Writeln( '4の倍数は2の倍数の部分集合か ', Values2 >= Values4 );
Writeln( '素数と2の倍数とは等しいか ', Values1 = Values2 );
Writeln( '奇数と2の倍数とは等しくないか ', Values3 <> Values2 );
Writeln( '奇数と2の倍数の補集合とは等しいか ', Values3 = ( AllValues - Values2 ) );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
素数は奇数の部分集合か FALSE 4の倍数は2の倍数の部分集合か TRUE 素数と2の倍数とは等しいか FALSE 奇数と2の倍数とは等しくないか TRUE 奇数と2の倍数の補集合とは等しいか TRUE Press any key to continue
この例にあるように、>=, <=, =, <> などの各演算子を用いて集合同士の包括関係などを知ることができます。 この例では補集合を求めるために全集合からある集合を「減算」していますが、これについては次の説で説明します。
集合型 その3
先ほど少し触れたように、集合型では集合同士の和・積・差を求めることもできます。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
type
// 列挙型
Musumes = ( Iida, Abe, Yasuda, Yaguchi,
Kago, Tsuji, Ishikawa, Yoshizawa,
Konno, Takahashi, Ogawa, Niigaki );
// 娘。の集合型
SetOfMusume = set of Musumes;
var
Fullnames: array[Musumes] of string = ( '飯田圭織', '安倍なつみ', '保田圭', '矢口真里',
'加護亜依', '辻希美', '石川梨華', '吉澤ひとみ',
'紺野あさ美', '高橋愛', '小川麻琴', '新垣里沙' );
Musume: SetOfMusume;
Minimoni: SetOfMusume;
Petitmoni: SetOfMusume;
Tanpopo: SetOfMusume;
// 集合にある要素を列挙するプロシージャ
procedure EnumerateMember( member: SetOfMusume );
var
m: Musumes;
c: integer;
begin
c := 0;
for m := Low(Musumes) to High(Musumes) do
begin
if m in member then
begin
Write( Fullnames[m], ', ' );
c := c + 1;
end;
end;
Writeln( '以上', c, '名' );
end;
// メインプログラム
begin
// 娘。全体を表す集合
Musume := [Low(Musumes)..High(Musumes)];
// ミニモニ。 (新旧含めて)
Minimoni := [Yaguchi, Kago, Tsuji, Takahashi];
// プッチモニ。
Petitmoni := [Yasuda, Yoshizawa, Ogawa];
// タンポポ
Tanpopo := [Iida, Yaguchi, Ishikawa, Kago, Konno, Niigaki];
// ミニモニ。とタンポポだったメンバー
EnumerateMember( Minimoni * Tanpopo );
// ミニモニ。かプッチモニだったメンバー
EnumerateMember( Minimoni + Petitmoni );
// タンポポ以外のメンバー
EnumerateMember( Musume - Tanpopo );
// いずれのユニットにも含まれなかったメンバー
EnumerateMember( Musume - ( Minimoni + Petitmoni + Tanpopo ) );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
矢口真里, 加護亜依, 以上2名 保田圭, 矢口真里, 加護亜依, 辻希美, 吉澤ひとみ, 高橋愛, 小川麻琴, 以上7名 安倍なつみ, 保田圭, 辻希美, 吉澤ひとみ, 高橋愛, 小川麻琴, 以上6名 安倍なつみ, 以上1名 Press any key to continue
このようにいとも簡単に集合の和・差・積を求めることができます。 当然のことですが、これらの演算は同じ型の集合型同士でしか演算できません。
最後におまけのサンプルを載せておきます。
// ド・モルガンの定理が成り立っているかを証明する
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
type
// byte型の集合
SetOfByte = set of byte;
var
AllValues: SetOfByte;
Values1: SetOfByte;
Values2: SetOfByte;
CompValues1: SetOfByte;
CompValues2: SetOfByte;
// メインプログラム
begin
// 1〜20までの数全体を表す集合
AllValues := [1..20];
// 素数
Values1 := [2, 3, 5, 7, 11, 13, 17, 19];
// 適当
Values2 := [1, 5, 6, 7, 9, 12, 14, 15, 17];
// Values1 の補集合
CompValues1 := AllValues - Values1;
// Values2 の補集合
CompValues2 := AllValues - Values2;
// ド・モルガンの定理の証明
Write( 'ド・モルガンの定理は ' );
if ( CompValues1 * CompValues2 ) = ( AllValues - ( Values1 + Values2 ) ) then
Writeln( '成り立っている。' )
else
Writeln( '成り立っていない。' );
Write( 'ド・モルガンの定理は ' );
if ( CompValues1 + CompValues2 ) = ( AllValues - ( Values1 * Values2 ) ) then
Writeln( '成り立っている。' )
else
Writeln( '成り立っていない。' );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
ド・モルガンの定理は 成り立っている。 ド・モルガンの定理は 成り立っている。 Press any key to continue
レコード型
レコード型は他の言語で言う構造体に相当するデータ構造です。 宣言方法は列挙型や集合型のようにtype文で「識別子 = record ... end;」として、record と end; の間でメンバの宣言を行います。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
type
// レコード型Musumeの宣言
Musume = record
Name: string;
Age: integer;
BirthDate: TDateTime;
end;
var
aibon: Musume;
konkon: Musume;
// 現在の年齢を計算する関数
function CalcAge( birthDate: TDateTime ) : Word;
var
age: Word;
by, bm, bd: Word;
ny, nm, nd: Word;
begin
DecodeDate( birthDate, by, bm, bd );
DecodeDate( Now, ny, nm, nd );
age := ny - by;
if ( bm > nm ) or ( ( bm = nm ) and ( bd > nd ) ) then
age := age -1;
result := age;
end;
// Musume型の値を表示するプロシージャ
procedure DisplayMusume( m: Musume );
var
by, bm, bd: Word;
begin
DecodeDate( m.BirthDate, by, bm, bd );
Write( m.Name );
Write( ' ', by, '年', bm, '月', bd, '日生まれ、' );
Writeln( m.Age, '歳' );
end;
// メインプログラム
begin
aibon.Name := '加護亜依';
aibon.BirthDate := EncodeDate( 1988, 2, 7 );
aibon.Age := CalcAge( aibon.BirthDate );
with konkon do
begin
Name := '紺野あさ美';
BirthDate := EncodeDate( 1987, 5, 7);
Age := CalcAge( BirthDate );
end;
DisplayMusume( aibon );
DisplayMusume( konkon );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
加護亜依 1988年2月7日生まれ、15歳 紺野あさ美 1987年5月7日生まれ、15歳 Press any key to continue
レコード型変数の使い方は、C/C++やVBの構造体の使い方と全く同じです。 さらに、Object Pascalではwith文がサポートされています。 ただ、これはVBと違って各メンバにアクセスする際には「.(ドット)」をつけてはいけません。
また、本題とは関係ないのですが、TDateTime型は日付を扱うためのデータ型です(実際にはDouble型のエイリアス)。 EncodeDate, DecodeDateプロシージャは年月日の各数値からTDateTimeの値を設定・取得するためのプロシージャです。 また、Now関数は現在の時刻を取得するための関数です。
あと、全く問題ないと思いますが、一応参考までに述べておくとレコード型は値型です。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
type
// レコード型Musumeの宣言
Musume = record
{ 省略 }
end;
var
aibon: Musume;
member: Musume;
// 現在の年齢を計算する関数
function CalcAge( birthDate: TDateTime ) : Word;
{ 省略 }
// Musume型の値を表示するプロシージャ
procedure DisplayMusume( m: Musume );
{ 省略 }
// メインプログラム
begin
aibon.Name := '加護亜依';
aibon.BirthDate := EncodeDate( 1988, 2, 7 );
aibon.Age := CalcAge( aibon.BirthDate );
member := aibon;
member.Name := 'あいぼん';
DisplayMusume( aibon );
DisplayMusume( member );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end
加護亜依 1988年2月7日生まれ、15歳 あいぼん 1988年2月7日生まれ、15歳 Press any key to continue
ポインタ型
Object Pascalにはポインタ型が存在します。 機能や動作はC/C++のポインタと同様です。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
var
// integer型変数
x, y, t: integer;
// integerのポインタ型変数
px, py: ^integer;
begin
// 変数に値を代入
x := 3;
y := 2;
// 変数のアドレスを取得
px := @x;
py := @y;
// ポインタから値を取得
t := px^;
px^ := py^;
py^ := t;
// 値を表示
Writeln( 'x = ', x );
Writeln( 'y = ', y );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
x = 2 y = 3 Press any key to continue
ありきたりな例ですが、ポインタ型を使用した例です。 まず、ポインタ型変数を宣言する場合には ^ 演算子を用いて「^型」とします。 そして、そのポインタ型変数に代入するための変数のアドレスを取得するには、「@変数」とします。 さらに、ポインタ型変数の指し示すアドレスにある値を取得するには「ポインタ変数^」とします。 宣言時と値の取得時に ^ 演算子をつける位置が異なることに注意して下さい。
また、文字型のポインタであるPCharは、ポインタ値の加減算や等価・非等価の評価も行えます。 しかし、これ以外のポインタ型ではC/C++のようにポインタ値の加減算を行うことはできません。 次の例はPChar型を利用したものです。
{$APPTYPE CONSOLE}
program LearningDelphi;
uses
SysUtils;
var
// 文字列
s: string;
// カウンタ用
i: integer;
// 文字型のポインタ型変数
p, pt: PChar;
begin
// 値を代入
s := 'This is a sample of pointer.';
// アドレスを取得
p := @s[9];
pt := p;
Writeln( 'p^ = ', p^ );
// ポインタ値を減算
p := p - 3;
Writeln( 'p^ = ', p^ );
// ポインタ値を加算
p := p + 1;
Writeln( 'p^ = ', p^ );
// ポインタ値は等しいか
Writeln( 'p = pt is ', p = pt );
// ポインタ自体の値
Writeln( 'p = ', p );
// 終了メッセージを表示
Write( 'Press any key to continue' );
Readln;
end.
p^ = a p^ = i p^ = s p = pt is FALSE p = s a sample of pointer. Press any key to continue