序論
型定義での動的配列は、とても役に立つ機能です。しかし、
バージョン1.00.0 より前の FreeBasic ではこれをサポートしていませんでした。もうすこし正確に言うと、以前のバージョンでは、これを直接サポートしていませんでした。
しかし、ポインタと関連メモリー関数を使うと、動的な配列を作ることができました。
配列は、単純に、あるデータ型をつかむ、メモリの連続するブロックです。
FreeBasic の配列は、配列の中に含まれたデータについて説明するのに、配列記述子を使用します。そして、あなたは、この同じテクニックを、型の中で動的配列を築き上げるのに、使用できます。
type-def の中で必要な 2 つの要素は、特定のデータ型へのポインタと、サイズ・インディケータです。
そして、ptr 項目を、メモリの 1 ブロックを必要なサイズに割り当てて、サイズ・インディケータ項目にそのサイズを保存するのに、使用できます。
サイズ項目は、配列に、いくつの要素が、現在あるかを、あなたに言うために使用されます。
配列が初期化されると、次に、あなたは、配列の各要素にアクセスするために、ポインタ・インデックスを、使用できます。
コードでポインタを取得
下のプログラムは、動的型定義配列を、作成して、初期化して、リサイズするステップを、例証します。
'型を定義します:
'サイズは、配列の現在のサイズです
'darray は、配列データを含むでしょう'
Type DType
size As Integer
darray As Integer Ptr
End Type
'型のインスタンスを作成します
Dim myType As DType
Dim As Integer i, tmp
'要素のための十分なスペースを作成します
myType.darray = CAllocate
(5, SizeOf(Integer))
'配列サイズ・インディケータに
'配列の長さを設定します
myType.size = 5
'配列にデータを読み込みます
For i = 0 To myType.Size - 1
myType.darray[i] = i
Next
'データを表示します
For i = 0 To myType.Size - 1
Print "darray[";i;" ]:";myType.darray
[i]
Next
Print "何かキー入力して下さい..."
Sleep
Print
'現在の配列サイズを保存します
tmp = myType.size
'今度は、配列をリサイズします
'myType.darray = Reallocate(myType.darray, 10)
myType.darray = Reallocate(myType.darray, 10 * SizeOf(Integer)) ' 編集者注:前行のコードはこれに変更されました
'長さ指示子を設定します
myType.size = 10
'新しい配分にデータをロードします
For i = tmp To myType.Size - 1
myType.darray[i] = i
Next
'コンテンツを表示します
For i = 0 To myType.Size - 1
Print "darray[";i;" ]:";myType.darray
[i]
Next
Print "何かキー入力して下さい..."
Sleep
'割り当てスペースを解放します
Deallocate myType.darray
End
コードはどう働くか
第一歩は、もちろん、type-def を定義することです:
Type DType
size As Integer
darray As Integer Ptr
End Type
これは、ただ例なので、型の中の 2 つの要素、サイズ・インディケータと配列ポインタ、しかありません。
配列ポインタが、Integer ptrと定義されるのに注意してください。
ポインタを、特定の型に、定義するときに、「型化された」ポインタを作成します。
コンパイラは、この型情報を使って、配列に置かれる値が、確実に有効になるようにチェックすることができます。そして、この情報は、ポインタ演算にも使われまず。
次のステップは、働く変数を定義することです。
Dim myType As DType
Dim As Integer i, tmp
ここで、型のインスタンスは作成されます、以下のコードで使われるいくつかの働く変数と同様に。
警告:
これを使用できるようになる前に、配列ポインタを初期化しなければなりません。
初期化されていない ptr を使うと、プログラム・クラッシュ、システム閉鎖、およびいろいろな悪いことが引き起こされる場合があります。
myType.darray = CAllocate
(5, SizeOf(Integer))
myType.size = 5
コードの、この 2 つの行は、5 つの整数を保持するために、配列ポインタを初期化します。
Callocate がセグメントをゼロに初期化するので、Callocate はメモリ・セグメントを割り当てるのに使用されます。
サイズ項目は、配列の現在の長さを保存します。
もちろん、整数のサイズで、割り当てたバイト数を、単純に割り算することで、配列のサイズを計算できるでしょう。しかし、型の中でサイズ・インディケータを使うと、よりきれいで、プログラムにおける計算を保存します。
For i = 0 To myType.Size - 1
myType.darray[i] = i
Next
コードのこの部分は、いくつかの値を配列に登録します。
あなたは、配列のサイズを保存することが、なぜコーディング・プロセスを単純化するかについて、見ることができます。
配列が、型化されたポインタなので、ポインタ・インデックス・メソッドを使って、配列にアクセスできます。ポインタ・インデックス・メソッドとは、ほとんど、事前に定義された配列にアクセスしているようなものです。
For i = 0 To myType.Size - 1
Print "darray[";i;" ]:";myType.darray
[i]
Next
この部分は、単に値を表示しているだけです。配列に値を登録するのに使ったものと同じやり方を使っています。
もちろん、これは、動的配列です。したがって、あなたは配列をリサイズできます。これは、まさにコードの次の部分でやっています。
tmp = myType.size
'myType.darray = Reallocate(myType.darray, 10)
myType.darray = Reallocate(myType.darray, 10 * SizeOf(Integer)) ' 編集者注:前行のコードはこれに変更されました
myType.size = 10
コードの最初の行は、配列の現在のサイズを保存します。それで、既存のデータが上書きされていない間に、新しいメモリセグメントを初期化できます。
あなたはすぐにこれを見るでしょう。
2行目は、メモリ・セグメントをリサイズするのに、
Reallocate 関数を使っています。これは、配列をリサイズします。
この場合、配列を、より大きくしています。
もちろん配列を、より小さくすることも、できます。
配列をより小さくする場合は、新しいセグメントで、少しのデータも失われていないでしょう。あなたは、そう予想したでしょう。
上のコードの最後の行は、サイズ・インディケータに、新しい配列サイズを保存しています。
For i = tmp To myType.Size - 1
myType.darray[i] = i
Next
ここで、古い配列サイズを保存した理由を見ることができます。
For 命令文では、初期化手続きは、新たに索引を加えながら、繰り返します。この間に、メモリ・セグメントの中に、データを保存します。
これは、通常の配列で、Redim Preserve 命令文を使うのに似ています。
For i = 0 To myType.Size - 1
Print "darray[";i;" ]:";myType.darray
[i]
Next
コードのこの部分は、単純に、新しい値を表示します。
Deallocate myType.darray
これはきわめて重要です。
あなたは、メモリリークを防ぐために、あなたのプログラムで作成した、割り当てられたメモリを、割り当て解除すべきです。
以上のプログラムを動かすと、下のように表示されます:
darray[ 0 ]:
0
darray[ 1 ]:
1
darray[ 2 ]:
2
darray[ 3 ]:
3
darray[ 4 ]:
4
何かキー入力して下さい...
darray[ 0 ]:
0
darray[ 1 ]:
1
darray[ 2 ]:
2
darray[ 3 ]:
3
darray[ 4 ]:
4
darray[ 5 ]:
5
darray[ 6 ]:
6
darray[ 7 ]:
7
darray[ 8 ]:
8
darray[ 9 ]:
9
何かキー入力して下さい...
最初の表示は、オリジナルの配列を見せます。
2番目の表示は、新たにリサイズされた配列を見せています。