FreeBASIC マニュアルのトップに戻る

FreeBASIC TutDynaArrayType

目次→教本→いっしょに学ぼうDynamic Arrays in Types←オリジナル・サイト

型による動的配列 左にメニュー・フレームが表示されていない場合は、ここをクリックして下さい

←リンク元に戻る プログラム開発関連に戻る

序論

型定義での動的配列は、とても役に立つ機能です。しかし、バージョン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番目の表示は、新たにリサイズされた配列を見せています。

非静的メンバーとしての動的配列項目は、fbc のバージョン 1.00.0 から、UDT 内でサポートされました

上に書いた例を、fbc バージョン 1.00.0 以降用に修正しました。
UDT の中の非静的メンバーとして動的配列項目を使います。(現在サポートされている機能です):

'型を定義 (fbc バージョン >= 1.00.0):
'darray は配列データを格納します
Type DType
    darray(Any) As Integer
End Type

'型のインスタンスを生成します
Dim myType As DType
Dim As Integer i, tmp

'要素のための十分なスペースを作成します
ReDim myType.darray(4)

'配列にデータを登録します
For i = 0 To UBound(myType.darray)
    myType.darray(i) = i
Next

'データを表示します
For i = 0 To UBound(myType.darray)
    Print "darray(";i;" ):"; myType.darray(i)
Next
Print "何かキー入力して下さい..."
Sleep
Print

'現在の配列上限を保存します
tmp = UBound(myType.darray)
'ここで配列をサイズ変更します
ReDim Preserve myType.darray(10)

'Load in data into new allocation
For i = tmp + 1 To UBound(myType.darray)
    myType.darray(i) = i
Next

'内容を表示します
For i = 0 To UBound(myType.darray)
    Print "darray(";i;" ):";myType.darray(i)
Next
Print "何かキー入力して下さい..."

Sleep


最後 sancho3 によるレビュー(2018年2月8日) 注:コードの誤りの修正と注記

いっしょに学ぼう に戻る
←リンク元に戻る プログラム開発関連に戻る

ページ歴史:2019-02-26 14:51:55
日本語翻訳:WATANABE Makoto、原文著作者:WikiRick(Rick Clark aka rdc)

ホームページのトップに戻る

表示-非営利-継承