Memory-02 構造体を初期化する

Q いろいろなデータを代入した構造体を初期化したいのですが、それぞれの要素に0や""を代入するのは面倒です。何かいい方法はありませんか?
A あります。ZeroMemory関数を使います。
どう使う?
Dim udtRect As RECT

With udtRect
    .left=50
    .right=200
    .top=180
    .bottom=350
End With
'この段階で 各要素にデータが代入されている

ZeroMemory(VarPtr(udtRect),Len(udtRect))
'この段階で 初期化完了

MsgBox NULL,Str$(udtRect.left),"サンプル"
'メッセージの内容は「0」
ではZeroMemoryの使い方から。
第1引数に初期化したい変数へのポインタ・第2引数に初期化するサイズを指定します。
「ポインタ」ですから、変数をそのまま指定するのではありません。
そもそも「ポインタ」とは何なのか?それは簡単に言えばその変数が属する「メモリ内の場所」のことです。
で、その居場所を取得するのがVarPtr(APIではありません)という関数です。

第2引数には初期化するサイズを指定するわけですが、そのサイズ取得のためにLen関数を使用しています。
これは文字列についてその長さを取得するために使いますが、構造体も含めた変数のサイズを取得することも可能です。

ここでの「初期化」というのは、「0で埋める」ということになります。しかし、0以外の「指定の値で埋める」ということもできます。
その場合にはFillMemory関数を使うことができます。

Dim udtRect As RECT

With udtRect
    .left=50
    .right=200
    .top=180
    .bottom=350
End With
'この段階で 各要素にデータが代入される

FillMemory(VarPtr(udtRect),Len(udtRect),128)
'この段階で 初期化完了

FillMemory関数はZeroMemory関数より1個引数が多いだけです。この第3引数の値を変えることで、埋められる値が変わります。
「0」を指定したら、ZeroMemoryの動作と同じになります。
しかし、0で埋めることはあっても他の値で埋めることは少ないのではないかと思います。しかし、一応紹介しておきました。


(補足 2004/06/06)
ここで紹介した方法では、構造体の配列についての初期化を行うことができません。
そこで、配列専用の方法もご紹介しておきます。

Dim udtRect[10] As RECT,i As Long

For i=0 To 10
    With udtRect[i]
        .left=50
        .right=200
        .top=180
        .bottom=350
    End With
Next
'この段階で 各要素にデータが代入される

ZeroMemory(VarPtr(udtRect[0]),VarPtr(udtRect[11])-VarPtr(udtRect[0]))
'この段階で 初期化完了

荒技です(爆)

構造体の中にByte型が定義されている場合、なんとLen関数では実サイズより大きい値が返される可能性があります。
Len関数の戻り値に要素数を掛けてサイズを決めると、メモリ破壊になる可能性があるので、ポインタの引き算を行ってサイズを決めています。
従って、配列ではないバージョンではメモリ破壊が平気で起こる可能性がある…と思われるでしょうが、実際には「パディング」という処理が行われるためにメモリ破壊にはなりません。
但し、配列のバージョンでは「パディング」が要素毎には行われないため、メモリ破壊の危険性があります。そこで荒技を使いました。
※それにしても、[10]で定義しているのに1を足して[11]のポインタから引き算しているのが荒技ですね(^^;;;;;
※まあ、エラーにならないし[11]の領域を書き換えている訳でもないので安全だとは思うのですが…。

(補足 2004/10/06)
AB4.0β1を使用して実験してみたところ、AB4.0で新しく実装されたSizeOf関数を使うことで荒技を使わずに動作させられます。
Len関数でも正しい値が返るようになっているようです。

Dim udtRect[10] As RECT,i As Long

For i=0 To 10
    With udtRect[i]
        .left=50
        .right=200
        .top=180
        .bottom=350
    End With
Next
'この段階で 各要素にデータが代入される

ZeroMemory(VarPtr(udtRect[0]),SizeOf(RECT)*11)
'この段階で 初期化完了

これならわかりやすくなっているでしょう。AB4をお使いの際は、こちらの方法をおすすめします。

メニューに戻る