VB6で未初期化の配列かどうかを判断する方法はないでしょうか?
○.netだと例外が出る様ですが、VB6には無さそうなので。
○UBOUNDは未初期化の配列だとエラー9になってしまいます。
○関数の頭でOn Error Gotoでエラー処理に飛ばすと
とりあえずエラーにはならないみたいですが・・・。
案1) エラートラップして判断する。
案2) あらかじめ、長さゼロの初期化済み配列を入れておく。
案3) API で判定。
こんにちは。
一次元目だけでしたら
こんな感じで
Dim arg() As Long
If Sgn(arg) > 0 Then
MsgBox "配列あり"
Else
MsgBox "無し"
End If
ReDim arg(0, 0)
If Sgn(arg) > 0 Then
MsgBox "配列あり " & UBound(arg)
Else
MsgBox "無し"
End If
こんな感じで・・・。
Redim Preserveの時などには配列の初期化、未初期化にかかわらず、
ReDim Preserve arg(cmnUBoundEx(arg) + 1)
とかで出来るはず・・・。
魔界の仮面弁士さんの言うところの案1です
Public Function cmnUBound(strAry() As Long) As Long
On Error GoTo cmnUBound_ERR
cmnUBound = UBound(strAry)
Exit Function
cmnUBound_ERR:
If Err.Number = 9 Then
cmnUBound = -1
End If
End Function
お二人ともありがとうございました。
特にYKさんの方法はまさに悩んでいた配列が
ingteger型の1次元配列ですのでそのまま使えます。
sgnのヘルプを見ると符号をバリアント型の値で返す
数値演算と説明がありましたが、未初期化の変数は
0になるということでしょうか?
試しに
Dim array1() aas integer
Dim intA as integer
intA=Sgn(array1)
MsgBox "Sgn(array1)=" & intA
とすると"Sgn(array1)=0"と表示されましたので
(直接MsgBoxにSgn(array1)を渡すとVBがアプリケーションエラー
で落ちてしまいました。)
とおりすがりさんありがとうございます。
たぶんご提示いただいた方法が一般的な方法な
気が致します。
よく関数の最後にエラー処理を記述しているのを
見かけるものですから。
エラー発生しても関数のその後の処理を続行する様な
ことはあまりないと思いますので。。。
初期化されてない/Eraseされた直後であるかどうかの判定そのものは、
Private Declare Sub CopyMemoryFromSafeArray _
Lib "kernel32.dll" Alias "RtlMoveMemory" _
(ByRef RetPointer As Long, ByRef Src() As Any, _
Optional ByVal Length As Long = 4&)
Function IsEmptyIntegerArray(ByRef ArrayOfInteger() As Integer) As Boolean
Dim pSafeArray As Long
Call CopyMemoryFromSafeArray(pSafeArray, ArrayOfInteger)
IsEmptyIntegerArray = CBool(0& = pSafeArray)
End Function
で、可能です。但し、こういうコードを書く手間をかけずに、あらかじめ
配列の状態の管理(UBoundの値の監視など)をしておくほうが楽ですし、
管理もしやすいでしょう。
K.J.Kさんありがとうございます。
>但し、こういうコードを書く手間をかけずに、あらかじめ
>配列の状態の管理(UBoundの値の監視など)をしておくほうが楽ですし、
>管理もしやすいでしょう。
おっしゃるとおりです。
本来はそうあるべきだと思います。
実は他の人の書いたプログラムのメンテナンスをしていて、
関数も長い関数で、でもリスクを考えるといまさら構造から修正するのは
危険だし。。。という事情がありました。
いろんな方にご意見を聞けて大変参考になりました。
とりあえず本件は解決済みにしておきます。