ウォーターサーバーとコーヒーマシンが一体化した画期的マシン >>

VBA フォームのボタン クリックイベント時に書き込んだ記述で、次のような記述があります。
Dim temp() as string
ReDim temp(0)
(next processing)

一度、イベントを処理した後(フォームは閉じません。)
再度ボタンをクリックして同じコードを実行すると前に行ったデータが消去されずに残っているようです。
ReDimで Preserve宣言を使っていないので内容が消去されると考えていました。
ReDimのまえに、
Erase temp
という処理を設けて対応しますが、
ローカルウィンドウやウオッチウィンドウでメモリがクリアされたか確認できていません。
ReDimとEraseの処理でどのような違いがあるのでしょうか?

どなたかよろしくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (4件)

----ヘルプより引用----


Eraseステートメント
固定サイズの配列の場合は要素を再初期化し、動的配列の場合は割り当てたメモリを解放します。
----------------------

今回は、動的配列なので、メモリ解放ですね。

----ヘルプより引用----
ReDim ステートメント
動的配列変数に対するメモリ領域の再割り当てを行います。プロシージャ レベルで使用します。
----------------------

通常は動的配列のサイズを変更する時に使います。
また、Preserve を付けない場合は値は残りません。

ReDim temp(0) ですが、Option Base 1 なら、エラーになります。
Option Base 0 (又は、省略)の場合、添え字 0 の要素が利用可能です。

UBound(temp) は 0 となります。
つまり、ReDimで配列の要素を 0 個にすることは出来ません。

ちなみに、Eraseした場合、UBound()はエラーになります。

Erase temp
Debug.Print UBound(temp) ' この行でエラー



>再度ボタンをクリックして同じコードを実行すると前に行ったデータが消去されずに残っているようです。

この部分が疑問ですね。

プロシージャ内で宣言した変数なら、プロシージャが終了した時点で捨てられるので、次のイベントに値が残ることはありません。

どこか別の場所に値が残っているのでは?
    • good
    • 0

こんにちは。



>再度ボタンをクリックして同じコードを実行すると前に行ったデータが消去されずに残っているようです。

こういう問題は、コードを見せるのが最低条件です。大方、配列変数を、モジュールレベルにおいているからだと思います。Erase と Redim の対比なんていうのは、意味がありません。

>Officeのヘルプは分量ある割りに役立たないのですよね

ヘルプは、VBAを理解し、イメージとして曖昧な記憶にあるものを、言葉にして確認するときに必要なものであって、それ自体をわからない人の説明にはなっていません。言い換えれば、次元の世界の違うモノです。モノは物でなので、形や大きさが存在しますが、目では見えません。

あえて、回答というなら、Redim と Erase の根本的な違いは何かというなら、その頻度が違います。Redim は、中・上級レベルの全体の中の 10% の使用率なら、もう片方は、Erase は、0.1 %ぐらいです。

なお、質問からだいぶお時間も経っているようですから、もし、問題が解決していない場合は、一旦、ここを終了して、再度、質問したほうがよろしいかもしれませんね。特に、補足側につけても、確認しづらいです。
    • good
    • 0

再度の登場です。


回答は出てますが一言。


>ReDim temp(0)とErase tempの働きは同じという認識でよろしいですか?

No2さんの回答にもありますが全然別の働きをさせるものです。

(1)ReDim temp(0)

   要素1個の配列再確保(この時、初期化される)

(2)Erase temp
   
   動的配列tempのメモリー開放なので極論を言えば初期かもなにもtemp自体がなくなる
   故にこの先、tempを使いたければ、tempの再宣言が必要になる

     現在しているように、

     Erase temp
     ReDim temp(0)

     としなければならない


動的配列は、ReDim temp(??)と宣言されたときに初期化されるので、初期化の処理は不要。
また、動的配列に限らず、今回のようなプロシージャで宣言された変数の適用範囲は、そのプロシージャの中のみなので、初期化の必要はない。


>Officeのヘルプは分量ある割りに役立たないのですよね

●間違ったことが書いてあることはありますが、熟読してそこに書いてあることを実際に試してみれば、大いに役に立つと思いますがねぇ・・(^^;;;



 
    • good
    • 0

>前に行ったデータが消去されずに残っているようです



何をもってそう判断したのか分からないので何なんですが、
何れにしろ新しいブックで以下を試してみれば一目瞭然です。

UserFormにCommandButtonをひとつ配置。

'-------------------------------------
Private Sub CommandButton1_Click()
 Dim temp() As String
  ReDim temp(1)
    temp(0) = "AAA"
    temp(1) = "BBB"
    MsgBox "x: " & temp(0)
  ReDim temp(0)
    MsgBox "y: " & temp(0)
End Sub
'------------------------------------------

RedimとEraseについてはヘルプに詳しく書いてありますので参照。
それでもなお不明な点があれば再質問してください。
 

この回答への補足

有難うございます。
試したところ、"y : "しか表示されませんでした。

Officeのヘルプは分量ある割りに役立たないのですよね。
では、
ReDim temp(0)

Erase temp
の働きは同じという認識でよろしいですか?

補足日時:2007/10/18 23:52
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QRedimした動的配列はEraseする必要があるのか

Visual Basic6(SP5)で開発を行っているものです。
時々、「メモリが"Read"になることができませんでした」と言うエラーメッセージと共にVisual Basicのアプリケーションが終了する不具合が発生します。メモリ操作関連のエラーだろうと社内で指摘されました。

怪しいかと思われるのは、ある動的配列をRedimし、解放する必要が無いのでEraseしていない点です。

動的配列は、RedimしたらEraseしないとエラーの元になり得るのでしょうか? 時間のある方、ご回答願います。

Aベストアンサー

多分、直接的には関係ないと思われます。
ポインタをまともに扱うことのないVBでは
領域侵害などが発生する機会が少ないからです。

過去に相当大きな空間(200M)をredimで確保したままにしたことがありますが、
ご質問のエラーに遭遇したことはありません。

もし疑うのであれば、memorycopy、Bitbltなどの
メモリ転送APIの方がよほどたちが悪いです。

redimの場合はOSが勝手にアドレス空間を確保してくれるはずなので、
それができていないとすれば重大な障害がある感じがします。

マシンに依存する問題の可能性も捨て切れません。
社内ということなので、この辺りの問題は切り分け済みでしょうが、
参考までに挙げてみました。

QVB6 配列を初期化したい

VB6でループさせて配列に値を入れて、計算させて最終的に求めたい値をRとします。そのときループで繰り返すためか同じ配列に値を入れてどんどん値がでかくなりRの値がおかしくなってしまいます;
おそらく問題は一回前に入れた配列がそのままのこってしまってるからなのだと思うのですが;
配列の中の値をクリアする方法はないものでしょうか?
一応、配列=0として初期化しようとしても値は変わらず前のが残ったままになってしまっています;
どなたかわかる方いらっしゃいましたらご回答宜しくお願いします

その他何かいい方法があればそれも教えていただけたらと思います

Aベストアンサー

Eraceステートメントを使用

  Dim a() as Long
  Dim s(100) as String
  Dim x() as Long

  Erase a     ’要素が0になる
  Erase s     ’要素が""になる

  Redim x(100) as Long

  Erase x      ’メモリを解放

注)VB2005の場合は動作が異なるので注意して下さい。

QEXCEL VBAで計算値を四捨五入、切り上げ、切捨てする方法

ネットで探してみたのですが、計算結果を四捨五入して特定のセルを
返すにはどうしたらいいのでしょうか?

Sub hokangosa()

Dim ZPS As Double
Dim ZPOS As Double
Dim DMN As Double
MsgBox (" >>> 補間誤差自動計算 <<< ")
MsgBox (" >>> 初期値入力します <<< ")
ZPS = InputBox(">>> ステップを入力してください<<<")
ZPOS = Sheet1.Cells(22, 4).Value
DMN = ZPOS / ZPS
Sheet1.Cells(23, 6).Value = DMN
End Sub

ここでDMNの値を四捨五入したいです。

またこれとは別に切上げ、切捨ても教えていただけるとありがたいです。

Aベストアンサー

DMN = Application.WorksheetFunction.Round(ZPOS / ZPS, 0)
で、四捨五入
DMN = Application.RoundDown(ZPOS / ZPS, 0)
で切り捨て
DMN = Application.RoundUp(ZPOS / ZPS, 0)
で切り上げです。

引数で、対象桁を変更できます。

QDoEvents関数って何?

こんにちは。

VBAやプログラミングに詳しい皆様に
教えていただきたい質問があります。

cells(1,1)からcells(5000,1)までの値を消去するときに
処理の進行状況を表示するためにuserform上にプログレスバーを表示したいと思います。

そこで下記のようなコードを入力しました。

userform1.show
for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
next i
unload userform1

しかしこれだとuserformの背景が真っ白になってしまい
ラベルの文字も消えてしまいます。
そこで「EXCEL VBA パーフェクトマスター」という本を見たら

for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
DoEvents
next i
unload userform1
と入力すれば解決することがわかりました。

しかし「DoEvents」についてあまり詳しく書いていなかったのでDoEvents関数をヘルプで見ると、
「発生したイベントがオペレーティング システムによって処理されるように、プログラムで占有していた制御をオペレーティング システムに渡すフロー制御関数です。」

と書いてあるのですが正直、書いてあることがよくわかりません。

どなたかDoEvents関数について、
もう少しわかりやすく教えていただけませんか。
それから、最初に書いたコードで実行すると
ユーザーフォームの背景が真っ白になってしまう原因も
教えていただけませんか?

よろしくお願いいたします。

こんにちは。

VBAやプログラミングに詳しい皆様に
教えていただきたい質問があります。

cells(1,1)からcells(5000,1)までの値を消去するときに
処理の進行状況を表示するためにuserform上にプログレスバーを表示したいと思います。

そこで下記のようなコードを入力しました。

userform1.show
for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
next i
unload userform1

しかしこれだとuserformの背景が真っ白になってしまい
ラベルの文字も消えてしまいます。
そ...続きを読む

Aベストアンサー

簡単に言うと、
OS に制御を渡すってことです。(ヘルプそのまんま)
時間が掛かるループ処理などの場合、ループが終わるまで制御は独占されてしまいます。
ですのでループ中は OS や Excel そのものにも再描画をさせる暇さえ与えません。
途中に DoEvents を入れると制御が OS に渡るので、OS は溜まっていた処理をそこで行うことができます。
結果、フォームの再描画などが行われることになります。

注意点ですが、
Private Sub CommandButton1_Click()
  Dim i As Long

  For i = 1 To 50000
    DoEvents
    Cells(i,1) = ""
  Next i
End Sub

Private Sub CommandButton2_Click()
  MsgBox "hoge"
End Sub

っていうフォームのコードがあった場合、
DoEvents を入れることによって、ループ中にユーザーがCommandButton2 を押すことによって CommandButton2 のクリック イベントも動いちゃいます。
CommandButton1 のクリック イベントではループの前に
CommandButton1.Enabled = False
CommandButton2.Enabled = False
を書いてフォーム上の CommandButton を無効にしておき、ループが終わったら
CommandButton1.Enabled = True
CommandButton2.Enabled = True
と書いて CommandButton を有効に戻してください。

これを工夫すれば、CommandButton2 で CommandButton1 のループを途中キャンセルする処理もすることができます。

Private Canceled As Boolean

Private Sub CommandButton1_Click()

  CommandButton2.Enabled = False

  Dim i As Long
  For i = 1 To 50000
    DoEvents

    If Canceled = True Then
      MsgBox "キャンセルしました"
      Exit Sub
    End If

    Cells(i, 1).Value = ""
  Next i
End Sub

Private CommandButton2_Click()
  Canceled = True
End Sub



コードの行頭にあるスペースは見易さのために全角スペースで作成していますので、これをこのままコピペするとエラーになるかもしれません。
コピペするなら行頭の全角スペースを半角スペースに直してください。

簡単に言うと、
OS に制御を渡すってことです。(ヘルプそのまんま)
時間が掛かるループ処理などの場合、ループが終わるまで制御は独占されてしまいます。
ですのでループ中は OS や Excel そのものにも再描画をさせる暇さえ与えません。
途中に DoEvents を入れると制御が OS に渡るので、OS は溜まっていた処理をそこで行うことができます。
結果、フォームの再描画などが行われることになります。

注意点ですが、
Private Sub CommandButton1_Click()
  Dim i As Long

  For i = 1 To 50000
...続きを読む

QVBA オブジェクトが空かどうか判定する

皆様のお知恵を拝借させてください。

エクセルVBAでオブジェクトを入れる変数を定義し、その変数にオブジェクト
が入っているかどうか検査したいのですがどうしたらいいでしょうか。

例えば---
Dim a As Workbook
If a <> nothing then ←この部分が分からない。このままだとエラー。
処理
End if
---------
環境
エクセル2003
WinXPsp1

Aベストアンサー

もし、aが空だったら
If a Is Nothing Then 

もし、aが空じゃなかったら
If Not a Is Nothing Then

QEXCELファイルのカレントフォルダを取得するには?

EXCELファイルのカレントフォルダを取得するには?

C:\経理\予算.xls

D:\2005年度\予算.xls

EXCEL97ファイルがあります。

VBAで
  カレントフォルダ名
(C:\経理\,D:\2005年度\)
を取得する事は可能でしょうか?

CURDIRでは上手い方法が見つかりませんでした。

Aベストアンサー

こんばんは。
Excel97 でも、同じですね。以下で試してみてください。

Sub test()
'このブックのパス
a = ThisWorkbook.Path
'アクティブブックのパス
b = ActiveWorkbook.Path
'Excelで設定されたデフォルトパス
c = Application.DefaultFilePath
'カレントディレクトリ
d = CurDir
MsgBox "このブックのパス   : " & a & Chr(13) & _
   "アクティブブックのパス: " & b & Chr(13) & _
   "デフォルトパス    : " & c & Chr(13) & _
   "カレントディレクトリ : " & d & Chr(13)
End Sub

QエクセルVBA 「On Error GoTo 0」について

「On Error GoTo 」ステートメントの意味は、だいたい理解しています。
「On Error GoTo 0」 ステートメントについて、ご教授お願いします。
参考書には「エラーのトラップ処理を無効にする」と載っていましたが、よくわかりません。
具体的にどのような使い方をするのか、簡単なコードで説明していただければ幸いです。
よろしくお願いします。

Aベストアンサー

#3の回答者ですが、コードのどこが原因か特定し、実行時エラーとして、そのエラーが不可避な場合において、On Error Resume Next を付けますから、On Error Goto ErrHandler よりも、扱い方が難しいです。当然、その部分だけの範囲を囲うので、On Error Goto 0 を入れると思いますし、今では、使う場面が限定されているはずです。

後はテキストを参考にしてください。当面、このようなコードが必要になることはないと思いますが。

QVB6.0-整数と余りを求める

表題の通り、整数と余りを求める関数を教えてほしいです:例:100/60=1余り40
整数:1
余り:40
よろしくお願いいたします。

Aベストアンサー

Dim A,B,C,D as integer
A=100
B=60
C=Int(A/B) <---答は1
D=A mod B

●IntはAをBで割った時の整数部分を求める関数ですが、答が負の場合は
注意が必要です。 例 Int(-100/40)=-2
これを回避する場合 Fixがいいです

●mod は A を B で割った時の余りを求める関数

QEXCEL VBAマクロ作成で、他のEXCELからデータを取り込みたい

メインプログラム(EXCEL VBA)より、
他のフォルダーにあるEXCELの項目の内容を取り込みたいです。
たとえば他のフォルダーのEXCELのRange("A2:A3").ValueをメインプログラムのRange("C2:C3").Valueにセットしたい時です。

・コマンドボタン押したら、どこのEXCELから取り込むかのポップアップ(?)は、表示はできてます。
・作業者が選んだパスとブックもMsgBoxで表示できてるので、もらう相手の場所も取得できてます。

・となると次はOPEN,INPUTですか?
テキストデータの取り込みですと、Inputでそのバッファを定義してるのですが、なんか違うような。。。

よろしくお願いします!

Aベストアンサー

私がやる方法です。

Dim writeSheet As Worksheet ' 自分自身の書き出し先シート
Set writeSheet = ThisWorkbook.Worksheets(1) ' Sheet1 を参照

Dim readBook As Workbook ' 相手ブック
Set readBook = Workbooks.Open(filename) ' 相手ブックを開いて参照
Dim readSheet As WorkSheet ' 相手シート
Set readSheet = readBook.Worksheets("sheetName") ' 相手シートを参照
' または Set readSheet = readBook.Worksheets(sheetIndex)

' 例えば
writeSheet.Cells(1, 1).Value = readSheet.Cells(2, 2).Value ' 相手シートの B2 の値を自分自身の A1 に書き込む

readBook.Close False ' 相手ブックを閉じる
Set readSheet = Nothing
Set readBook = Nothing

私がやる方法です。

Dim writeSheet As Worksheet ' 自分自身の書き出し先シート
Set writeSheet = ThisWorkbook.Worksheets(1) ' Sheet1 を参照

Dim readBook As Workbook ' 相手ブック
Set readBook = Workbooks.Open(filename) ' 相手ブックを開いて参照
Dim readSheet As WorkSheet ' 相手シート
Set readSheet = readBook.Worksheets("sheetName") ' 相手シートを参照
' または Set readSheet = readBook.Worksheets(sheetIndex)

' 例えば
writeSheet.Cells(1, 1).Value = readSheet.Ce...続きを読む

Qメモリの解放について VB6 VBA

VB6やVBAで動的配列をERASEしたのですが、タスクマネージャーで見ても使っているメモリを解放しているように見えません。
動的配列の内容をMsgBoxで表示させるたびにメモリがどんどん減っていきます。Eraseしても戻りません。
Redim ArryaDat(0)とかでも無理でした。
APIを使って(どんな方法)でも、メモリを解放したいのですが、可能でしょうか?

Dim ArrayDat() as String

Redim ArrayDat(100)
ArrayDat(0) = "なんとか"
ArrayDat(1) = "かんとか"
...
ArrayDat(100) = "メモリを解放したい"

for i = LBound(ArrayDat) to UBound(ArrayDat)
MsgBox("どんどんメモリが消費されていく・・ [" & ArrayDat(i) & "]")
next i

Redim ArrayDat(0)
Erase ArrayDat
NsgBox("解放したつもり? 誰か教えて")


あと、.NETではメモリ解放はどうなっているのでしょうか?
まだ使いませんが、頭の片隅に入れておきたいです。

VB6やVBAで動的配列をERASEしたのですが、タスクマネージャーで見ても使っているメモリを解放しているように見えません。
動的配列の内容をMsgBoxで表示させるたびにメモリがどんどん減っていきます。Eraseしても戻りません。
Redim ArryaDat(0)とかでも無理でした。
APIを使って(どんな方法)でも、メモリを解放したいのですが、可能でしょうか?

Dim ArrayDat() as String

Redim ArrayDat(100)
ArrayDat(0) = "なんとか"
ArrayDat(1) = "かんとか"
...
ArrayDat(100) = "メモリを解放したい"

f...続きを読む

Aベストアンサー

Erase は、配列の要素をクリアしただけで、エリアとしては
確保されています。
完全に解放させるには、Nothingを代入させないと解放されません。
Set ArrayDat = Nothing

また、APIでメモリ解放する場合は、APIを使って割り当てたメモリ
で良く使用しますが、今回の場合は、そこまで行っていないと
思います。

ご検討下さい。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング