- ベストアンサー
SGN関数を使った2つの動的配列の初期化判定
- Excel VBAで2つの動的配列を同時に初期化する方法について質問があります。
- SGN関数を使用して初期化状態を判定する際に、正しく評価されない現象が発生しています。
- 現象が発生する理由や、解決策について教えていただきたいです。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
>こちらのやろうとしていることとは少し異なってしまっています(とはいえUboundの後err.Numberで判定すればいいのでこれからはsgn関数を使うのをやめることにします。 論理と結果の表示に矛盾があるのではないでしょうか? 下記のコードで試してください。 Sub test() Dim a() As Integer Dim b() As Integer Dim myarray() As Variant ReDim myarray(0) ReDim a(100, 10, 50) ReDim b(2, 10) Erase a ' Eraseをコメントアウトして比較します。 Erase b ' 〃 On Error Resume Next ' エラー発生時にエラーを解除して次のステップへ err_a = -1: err_a = UBound(a, 1) ' エラー発生時はerr_aの値がそのまま残る If err_a = -1 Then ' 配列aをEraseで開放するとUBound(a,1)でエラー発生 MsgBox "配列変数 a は要素数が定義されていません。" End If err_b = -1: err_b = UBound(b, 1) If err_b = -1 Then MsgBox "配列変数 b は要素数が定義されていません。" End If err_a = -1: err_a = UBound(a, 1) err_b = -1: err_b = UBound(b, 1) If err_a = -1 And err_b = -1 Then MsgBox "配列変数 a と b は要素数が定義されていません。" Else: If err_a = -1 Or err_b = -1 Then MsgBox "配列変数 a と b の何れかの要素数が定義されていません。" End If On Error GoTo 0 End Sub ReDim a(0) で配列の再設定をすると UBound(a,1) でエラーにならず、0が帰ります。 また、ReDim Preserve myarray(10) のようにすると既存の配列値を残して配列をリサイズしますのでReDimでは初期化にならないと思います。 何かの役に立てば幸いです。
その他の回答 (3)
- bunjii
- ベストアンサー率43% (3589/8249)
>redimしていない場合はUboundを使うとエラーが出てしまいます。 質問に提示のコードについて動作を確認しましたところ下記の誤りがありました。 If Sgn(a) = 0 Then MsgBox "配列aは初期化されていません。" 配列aが未使用のときはSgn(a)で0が帰りますので"初期化されていません。”と判定されます。 ReDim a(0)で配列の初期化をすると0以外の値が帰りますので逆の判定になります。 Sgn(a) = 0 → Sgn(a(0)) のように1つの要素を対象に変更すると0が帰りますが、未使用の場合はエラーになります。(UBoundと似たようなエラーです) >やはりSGN関数を判定に使わない方がいいのかもしれまんせんね。 下記のコードで試してください。 Dim a(), b() As Integer ReDim a(10) For i = 1 To 10 a(i) = i Next i 'Erase a, b ' コメントアウトを解除したときと比較する 'ReDim a(0), b(0) ' コメントアウトを解除したときと比較する an = 0: bn = 0 On Error Resume Next an = UBound(a, 1): bn = UBound(b, 1) On Error GoTo 0 MsgBox "配列の要素数は a " & an & ",b は" & bn & " です。" If an <> 0 Then MsgBox "配列aは初期化されていません。" If bn <> 0 Then MsgBox "配列bは初期化されていません。" If (an * bn) <> 0 Then MsgBox "配列a,bは両方共初期化されていません。" If (an + bn) <> 0 Then MsgBox "配列a,bはいずれかが初期化されています。" Else: MsgBox "配列a,bは両方共初期化されています。" End If
お礼
返信が遅くなりまして申し訳ありません。 初期化という言葉使ったのがまずかったのですが、 私が行いたいのは配列が空っぽ(宣言やeraseをしてからredimを一度も指定ない状態)を2つ同時に判定しようとするときにsgn関数を使うとおかしな結果がでるという話でした。そちらが提示されたプログラムを実行してみましたが、Erase a,bをコメントアウト解除した時とredim a(0),b(0)をコメントアウトを解除した時でどちらも「配列a,bは両方共初期化されています。」というメッセージがでてしまっており、こちらのやろうとしていることとは少し異なってしまっています(とはいえUboundの後err.Numberで判定すればいいのでこれからはsgn関数を使うのをやめることにします。ありがとうございました。
- bunjii
- ベストアンサー率43% (3589/8249)
>Excelのvbaにおいて2つの動的配列を同時に初期化(redimされているか)どうか判定するときにsgn関数を使うとおかしな現象が起こります。 Sgn関数の戻り値は-1、0、1の3種です。 従って配列の値が0の場合とSgn関数の戻り値が混同しますので初期化の判定には不向きと思います。 UBound関数でサイズを確認する方が確実でしょう。 ReDim a(0) ReDim b(0) (UBound(a) = 0) And (UBound(b) = 0) で試してみると良いでしょう。
補足
redimしていない場合はUboundを使うとエラーが出てしまいます。 On error resume next でerr.numberで判定すればいいという意見があるかもしれませんが。 やはりSGN関数を判定に使わない方がいいのかもしれまんせんね。
- Hayashi_Trek
- ベストアンサー率44% (366/818)
Sgn関数の引数に配列を渡しているけど、エラーにならないんですか? VBAのヘルプでは、「任意の数式を指定できる」となっているが配列は対象外では?
補足
動的配列を初期化(redim)されているかどうかを判定するのにsgn関数を使うというのはよく聞くテクニックなのですが、確かにSGN関数の本来の使い方とは異なるようです。だからこそ、どうしてこうなるのか仕組みを理解しておきたいのです。「not not」を使うなんて方法も書いてあるサイトもありますがこちらもどうしてこうなるかはよくわかっておりません。動的配列を初期化されているかどうか明確な方法が他にあるということであればもちろんそちらを使います。
お礼
何度もコードを提示してくださりありがとうございます。 確かにこれで目的の動作が可能になります。 これからは提示してくださったコード参考にプログラムを組んでみようと思います。