VBAの変数の定義について

このQ&Aのポイント
  • VBAでの変数の定義についてお尋ねします。VBAの勉強を始めたばかりの超初心者です。
  • (1)下記はモジュールレベルでの変数の宣言になると思いますが、変数の定義?例えば、最終値 = Range("A4").End(xlDown).Rowはそれぞれのプロシージャで定義しなければならないのでしょうか?(2)モジュールレベルでの変数の宣言は,Dimではなく、Privateでやるべきなのでしょうか?(3)何か指摘事項があれば、教えてください。
  • 超初歩的な質問で、申し訳ありませんが、よろしくお願いいたします。
回答を見る
  • ベストアンサー

VBAの変数の定義について

いつもお世話になっております。 VBAでの変数の定義についてお尋ねします。 VBAの勉強を始めたばかりの超初心者です。 I.チェック:A列とC列の和をE列に記載してその正誤を判定。 II.リセット:E列をクリアし、A列、C列の数字をランダムに置き換える。 という練習問題のコードを私が書いたものです。 以下について質問させていただきます。 (1)下記はモジュールレベルでの変数の宣言になると思いますが、変数の定義?例えば、最終値 = Range("A4").End(xlDown).Rowはそれぞれのプロシージャで定義しなければならないのでしょうか? (2)モジュールレベルでの変数の宣言は,Dimではなく、Privateでやるべきなのでしょうか? (3)何か指摘事項があれば、教えてください。 超初歩的な質問で、申し訳ありませんが、よろしくお願いいたします。 Option Explicit Dim i As Integer '処理用カウンタ変数 Const 初期値 As Integer = 4 '表の最初 行 Dim 最終値 As Integer '表の最終 行 Sub チェック() 最終値 = Range("A4").End(xlDown).Row '表の最終行番号を取得 For i = 初期値 To 最終値 Step 1 If Cells(i, 1).Value + Cells(i, 3).Value = Cells(i, 5).Value Then 'A列+B列 Cells(i, 5).Font.Color = vbBlue '回答が正ならフォントを青 Else Cells(i, 5).Font.Color = vbRed '回答が誤ならフォントを赤 End If Next i End Sub Sub リセット() 最終値 = Range("A4").End(xlDown).Row '表の最終行番号を取得 For i = 初期値 To 最終値 Step 1 Cells(i, 5).ClearContents '回答をクリア Cells(i, 5).Font.Color = vbBlack '回答のフォントを黒 Cells(i, 1).Value = Int(Rnd * 100) 'A列にランダムな数値 Cells(i, 3).Value = Int(Rnd * 100) 'C列にランダムな数値 Next i End Sub

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

こんにちは。 後出し回答で、ややこしくなるだけのようでもあるのですが、一応、他の方の大方の意見とは食い違いはありませんが、細かい点を言及しています。 >VBAの勉強を始めたばかりの超初心者です。 という条件でお話を書かせていただきます。つまり、上級レベルでどうこういう話をサイズダウンして持ってきても、話を通じにくいように思います。 >VBAでの変数の定義 細かい話で恐縮ですが、Dim などで、変数をつけることを「変数の宣言」と言います。 >変数の定義?例えば、最終値 = Range("A4").End(xlDown).Rowはそれぞれのプロシージャで定義 前述の通り、この場合は、もちろん、変数に「代入」という言いますが、私は、このような場合は、それぞれのほうがよいのですが、ひとつのプロシージャにまとめるつもりなら、その限りではありませんが、入門レベルとおっしゃるなら、それは手をつけないほうがよいです。 > Dim i As Integer '処理用カウンタ変数 > Const 初期値 As Integer = 4 '表の最初 行 > Dim 最終値 As Integer '表の最終 行 「 i」 のカウンタ変数、「最終値」も、可変ですから、プロシージャの中に入れてください。 >Dimではなく、Privateでやるべきなのでしょうか? Privateとつけるべきのような回答もありますが、入門レベルでは、そのような状況に至っているのでしょうか?下のサンプルでは、共有する部分として、定数で、Private は使っていますから、話が矛盾しているようですが、やむを得す使いました。 どちらかというと、私は、明示的意味で、Public やPrivate 変数に付けています。当然、Private(モジュールレベル)でつける状況の時は、必ず、Private ステートメントを付けますが、入門や初級レベルでは、おそらくほとんど出てこないはずです。意味をよく分かって使うに限ります。これは、逆に、排他的に使用するという意味合いが含まれています。 >.Valueプロパティ これは、初心者ならとかもく、暗黙的なプロパティは、省略しません。私が、VB6を使ってExcelを動かす時に、エラーに出会うのは、この.Valueプロパティの省略が原因だった記憶があります。省略が可能なのは、そのアプリケーション内だけに限ります。オートメーション化した時に、不明なエラーを発生する確率が高くなります。VBAを本格的に書きたいのなら、Valueプロパティの省略を勧めません。また、.Value値の他に、.Value2 や .Text などがありますから、それらを区別する(明示的にする)ためにも必要です。 > Integer型かLong型か 昔は、行はLong型、列はInteger型と言っていた時代がありましたが、少なくとも、32bitOSの場合、16bitのInteger型は内部で32bit変換されながらコードが実行されます。32bitのLong型はこのオーバーヘッドがない分、高速であるといわれています。Integer型のエラー値を必要な以外はに、すべてLong型にしてください。 >プロシージャ名で、2byte文字 プロシージャ名で、2byte文字を使うのは初心者のみです。一部、エラーの発生する2byte文字(漢字)があるということです。その漢字が、何かは知りませんが、私の記憶では、特殊な漢字だとかきいたことがあります。調べれば出てくるはずです。プロシージャ名や変数の付け方には、それなりにルールがありますが、初心者にはそれは言わないことにします。 >Randomize 乱数ジェネレータを初期化 (乱数系列を再設定) する数値演算ステートメントです。 Randomize は、1つのプロシージャ上で、1回だけです。2回以上すると、初期化してテーブルが元に戻るせいなのか、一様乱数(指定の数値の間を区切った乱数)が桁数が少ないと同じ数字が多くでることがあるようです。1回だけにしてください。 元のマクロから、こちらで手をいれてみました。 '// Option Explicit Private Const INIT As Long = 4 '初期値 Sub Initializing() '初期化 Dim i As Long Dim LastRow As Long   LastRow = Range("A4").End(xlDown).Row   If LastRow = Rows.Count Then Exit Sub '空の場合のエラー処理   Application.ScreenUpdating = False   Randomize '←ループの中にはいれない   For i = INIT To LastRow     Cells(i, 5).ClearContents     Cells(i, 5).Font.ColorIndex = xlColorIndexAutomatic        Cells(i, 1).Value = Int(Rnd * 100) '2桁の乱数     Cells(i, 3).Value = Int(Rnd * 100) '2桁の乱数   Next i   Application.ScreenUpdating = True End Sub '// Sub CheckingNumbers() '計算チェック Dim i As Long Dim LastRow As Long   LastRow = Range("A4").End(xlDown).Row   If LastRow = Rows.Count Then Exit Sub   Application.ScreenUpdating = False   For i = INIT To LastRow     If Cells(i, 1).Value + Cells(i, 3).Value = Cells(i, 5).Value Then       Cells(i, 5).Font.ColorIndex = 5 '正-青 ColorIndexを使う     ElseIf Cells(i, 1).Value + Cells(i, 3).Value <> Cells(i, 5).Value Then       Cells(i, 5).Font.ColorIndex = 3 '誤-赤     Else       Cells(i, 5).Font.ColorIndex = xlColorIndexNone     End If   Next i   Application.ScreenUpdating = True End Sub '// おそらく、このマクロは、同じ発想のものから生まれたのだから、これらを統合できないかと思うなら、分からないわけではないのですが、煩雑になりますから、この程度でよいと思います。

genta1019boston
質問者

お礼

ご丁寧な回答ありがとうございました。

その他の回答 (3)

回答No.3

>(1)下記はモジュールレベルでの変数の宣言になると思いますが、変数の定義?例えば、…… 定義と言うと、どこのことなのか意味が曖昧なので、No.1 さんのおっしゃるとおり、代入と言えば明瞭かつ正確ですね。 そもそも、モジュール内の他のプロシージャを呼び出すという目的のためにプロシージャ間で変数を共有する必要があるといった場合に、モジュールレベルでの宣言を行います。プロシージャ間で変数が独立している(スコープがプロシージャ内のみである)状態で構わないという場合は、たとえ同じ名前の変数を使うとしても、それぞれのプロシージャ内で宣言するものです。むやみにモジュールレベルにしても、バグを生むだけです。 >例えば、最終値 = Range("A4").End(xlDown).Rowはそれぞれのプロシージャで定義しなければならないのでしょうか? 「ならない」ということはないです。変数「最終値」がモジュールで宣言されているのであれば、ご質問の 1 行のみの処理を行う短いプロシージャを用意し、Call ステートメントで呼び出すこともできます。しかし、こんなに簡潔な行と、質問文に載っているこんなに短いプロシージャだけで問題にされている検討事項なのだとすれば、そんなふうにあえて別の場所に分けたりしないほうが、読みやすいでしょう。 >(2)モジュールレベルでの変数の宣言は,Dimではなく、Privateでやるべきなのでしょうか? Dim でも同じ機能になるので大丈夫ですが、私を含め、モジュールレベルならなるべく Private で書くという人も多いかもしれません。両者の役割分担という観点から。また、モジュールレベルの Dim は Private Dim の省略という意味合いなので、始めから Private と書いたほうが意味的にも理解しやすいという面もあるかもしれません。 その他の詳細な情報については、次ページなどをご覧ください。 http://www.asahi-net.or.jp/~ef2o-inue/vba_k/sub04_050_04.html >(3)何か指摘事項があれば、教えてください。 6 点ほど。 1. Long より Integer のほうが有利ということは、ありません。個人の流儀はいろいろあるのかもしれませんが、Integer で書ける箇所は何でもかんでも Long に書き換えてしまったとしても、悪くはないです。したがってシートの行列番号を代入する変数には、数値の最大値の制限を考えて、Long を指定するのが普通です。 2. プロシージャ名に全角文字を使うと、バージョンの異なるファイルで実行する場合とか何かの加減で、不具合の原因になる可能性があるとの話も聞きます。 3. 「Step 1」は、省略することも可能です。「Step 3」とか「Step -1」とか、「1」でない場合は、省略しません。 4. Cells(i, 1) は、Cells(i, "a") と書くこともできます。同じ行のコメントには「A列+B列」と載っていますが、コードを見ると実際には、A 列、C 列になっていますね。 5. Rnd 関数を使う場合は、通常、Randomize ステートメントを併用します。そうしないと、乱数系列が更新されていきません。具体的には、次ページなどをご覧ください。 http://www.relief.jp/itnote/archives/013898.php 6. 「.Value」は私もなるべく付けるよう心掛けています。

genta1019boston
質問者

お礼

ご丁寧な回答ありがとうございます。

回答No.2

2個のプロシージャ間で変数を共有するのは、出来るだけ避けるべきです。共有すると全体での型宣言が必要となり、個々のプロシージャで宣言が重複しないよう気を配る必要が出るし、後で片方のプロシージャのみ他所で再利用したい場合に、変数の処理をする必要があります。 という考えで質問文のソースコードを読むと、まずカウンタ用のiは個々のプロシージャ内で宣言すべきです。Constはそのままでもいいと思います。後で変更された時に一か所だけ共通の場所を変更するだけで済みますから。最終値は共通の値ですが、欲しい時に取得出来るため、個々のプロシージャ内で宣言すべきです。 整数の型宣言はintegerでもOKですが、数字の範囲の広いLongを勧めます。昔だったらメモリ容量に気を使って少なくて済む部分はintegerでしたが、今はそんな心配ありません。むしろintegerで大丈夫な範囲か?と心配する手間を省いた方が楽です。 .Valueは省略可。ことさら強調したい場合を除き使わない傾向です。 .colorと区別するために使いたかったのでしょうか。 可読性の有無で決まると思います。

  • yokomaya
  • ベストアンサー率40% (147/366)
回答No.1

>変数の定義?例えば、最終値 = Range("A4").End(xlDown).Rowはそれぞれのプロシージャで定義しなければならないのでしょうか? 定義・・、代入でよろしいかと。 仮に片方だけにそれを記述したとして、もう一方が先に呼ばれないことをどう保障する おつもりですか? 方法論としては initializeやWorkbook.openなど特別な最初に必ず実行される部分に記述する という手法が採れるなら、一か所の記述で済ませる事も、考えられなくはないですが この場合では素直に両方に記述が妥当と思いますよ。 普通は別の場所でそんなややこしい事をすると、後で読んでどうなっているのか掌握に困るだけです。 >モジュールレベルでの変数の宣言は,Dimではなく、Privateでやるべきなのでしょうか? dim も Privateだと思いますよ。変数のスコープといいますが、変数の見える範囲が Publicだとどこからでも見えるけれど、そのモジュール内でしか見えないPrivateという意味です。 指摘したいのは あっちでも、こっちでも使うからといっても iはモジュール内でdim宣言するのが、妥当です。 ループ変数は意味なく使うからiで済ませますが、同じものを使う慣習をつけると 途中で別のサブを呼んだら書き換えられたなど、問題を起こす温床になりかねませんので。

genta1019boston
質問者

お礼

早速の回答ありがとうございます。

関連するQ&A

  • VBA (Row とRowsの違いについて)

    いつもお世話になっております。 VBA初心者ですが、RowとRowsの違いについて今一つ分かりません。 添付ファイルのように、A2:A25まで数字を入れた表を作って、今ある知識で行数をカウントするコードをいくつか書いてみました。 test1:A2から始まる表を構成するトータル行数を返す。 test2:?? test3:A2から始まる表の最終行番号を返す。 test4:test1と同じ test5:??? (1)test2、5は同じ内容のコードになると思いますが・・結果の『2』は何を意味しているのか分かりません。 (2)RowとRowsの違いは簡単に言うとどういう事でしょうか? まとまりの無い文章で申し訳ありませんが、よろしくお願いいたします。 Sub test1() Cells(2, 2).Value = Cells(2, 1).CurrentRegion.Rows.Count End Sub Sub test2() Cells(2, 3).Value = Cells(2, 1).CurrentRegion.Row End Sub Sub test3() Cells(2, 4).Value = Cells(2, 1).End(xlDown).Row End Sub Sub test4() Cells(2, 5).Value = Range(Cells(2, 1), Cells(2, 1).End(xlDown)).Rows.Count End Sub Sub test5() Cells(2, 6).Value = Range(Cells(2, 1), Cells(2, 1).End(xlDown)).Row End Sub

  • 取得した変数の値の一番大きい変数を取る

    エクセル2002使用です。 セル(A~F列)にランダムに入力された列の最終行数を変数で取っています。 その中で最も大きい変数の値を取るコードを記述したいのですが、 良い方法がわかりません。 sub test() Dim rcnt1, rcnt2, rcnt3, rcnt4, rcnt5, rcnt6, rcnt As Integer '最終行の取得 rcnt1 = Cells(65536, 1).End(xlUp).Row rcnt2 = Cells(65536, 2).End(xlUp).Row rcnt3 = Cells(65536, 3).End(xlUp).Row rcnt4 = Cells(65536, 4).End(xlUp).Row rcnt5 = Cells(65536, 5).End(xlUp).Row rcnt6 = Cells(65536, 6).End(xlUp).Row rcnt = "最も大きい変数の値" ←ここがわかりません。 end sub よろしくお願いします。

  • VBAで行を挿入する

    VBAを始めた初心者です。 Exel2002使用です。 VBAでA列の4行目から10行目に行の挿入をできるようにしようと下記のように書きましたが、Rows("i:i").Selectの部分でデバックがかかってしまいます。間違っている理由がわからないのですがよろしくお願いします。 また、DO While Loopステートメントを使ってA列が空白になるまで(例えばA4セル以下の)行を挿入とする場合の方法も教えていただけましたら幸いです。 Sub 4行目から10行目まで() Dim i As Integer For i = 4 To 10 Cells(i, 1).Value = i Rows("i:i").Select Selection.Insert Shift:=xlDown Next i End Sub Sub 4行目から空白になるまで() Dim i As Integer Range("A4").serect Do While activecell.value = "" Cells(i, 1).Value = i Rows("i:i").Select Selection.Insert Shift:=xlDown activecell.offset(1,0).select Loop End Sub

  • 【VBA】範囲選択し降順で並び替え

    A列の最初の行から、F列の最終行迄を範囲選択し、C列降順で並べ替えをしたいです。最終行は、C列の最終行を指定します。 下記、「Rangeから始まる行」でエラーとなる為、ご教示宜しくお願いします。 Sub 使用頻度で並べ替え() Dim FastRow As Integer Dim LastRow As Integer FastRow = Cells(1, 1).End(xlDown).Row LastRow = Range("C" & Rows.Count).End(xlUp).Row Range("A & FastRow:F" & LastRow).Sort Columns("C"), xlDescending, Header:=xlNo End Sub

  • VBAと罫線の作成

    こんにちは。 VBA勉強中で初心者です。 今、以下の上段画像のような表をエクセル2003 で作成しました。 下段画像はVBA実行後の表です。 表は 番号と氏名、合否の結果を入力した ものです。 今、行いたい処理なのですが (1) B列の氏名欄に対応する、連番を A列に表示したい。 (2) さらに、氏名欄が入っている部分を A列からD列まですべてを罫線(普通線) で囲みたい。 の2点です。 (1)はなんとかできたみたいのですが、 (2)で完全に手が止まってしまいました。 最終の行と列の取得が、すこしわからないので 教えていただければと思います。 よろしくお願いします。 Sub sample() Dim num As Integer '行変数を設定 Dim num2 As Integer '番号変数を設定 Dim i As Long 最終行の取得? num = 4 'B列4行目から調べる num2 = 1 '連番は「1」からスタート Range("A:a").Clear 'A列のデータをいったんクリアにする Do Until Cells(num, 2) = "" 'B列の氏名欄が空白なるまで処理を繰り返す Cells(num, 1) = num2 '連番「1」をB4にまず、代入する num = num + 1 '行を1行分下げる num2 = num2 + 1 '番号変数に1をプラスする Loop i = Range("B4").End(xlDown).Row End Sub

  • 全くの初心者ですVBA

    どこが悪いかわかりません。 教えてください。 Sub テスト() Dim kekka As String Dim i As Integer tokuten = Worksheets("Sheet1").Cells(i, 1).Value For i = 1 To Worksheets("Sheet1").Range("A1").End(xlDown).Row.Count If tokuten >= 80 Then kekka = "合格" Else kekka = "不合格" kekka = Cells(i, 2) End If Next i End Sub シート1の A列に数値で得点が入っています。

  • VBA Next For でのコピペについて

    EXCEL VBA初心者です。 AシートEW44からGD44までをコピーしてBというシートの最終行へコピーしたいです。 今下記のように組んでいるのですが、うまく作動しません。 Private Sub CommandButton1_Click() Dim i As Integer For i = 153 To 186 row1 = Worksheets("B").Cells(Rows.Count, 27).End(xlUp).Row Worksheets("A").Cells(i, 44).Value = Worksheets("B").Cells(row1 + 1, 27).Value Next i End Sub アドバイスいただけませんでしょうか。

  • VBAプロシージャの間違いを添削願います

    A列からD列にかけてデータが入力されます。B列には4桁の数値が入力されており、 この4桁の数値を利用して、次のようにデータを管理したいと思います。 1.4桁の数値が同じものを抽出する。 2.抽出された数値は、最初に出現している数値の下の行に挿入する。 3.最初に出現している数値以外は削除する。 4.各行は空行が無い状態とする。 これをプロシージャにしたものが下記です。 Sub 重複行削除() Dim lastgyou As Integer Dim i As Integer Dim j As Integer Dim atai As Integer lastgyou = Range("B1").End(xlDown).Row For i = 1 To lastgyou - 1 atai = Cells(i, 2).Value For j = i + 1 To lastgyou If atai = Cells(j, 2).Value Then If j <> i + 1 Then Rows(j).Cut Rows(i + 1).Insert Shift:=xlDown End If i = i + 1 End If Next j Next i End Sub としましたが、重複行が削除されません。 ご教授をお願いいたします。

  • エクセルマクロ配列で変数は使えますか

    エクセル2013です。 初めて配列を使います。 以下のように作成し思ったようにできました。 Sub 計算() '成功 Dim a As Integer Dim c As Integer Dim b(5) As Integer Dim 最終行 Dim 値列  値列 = 17 最終行 = Cells(Rows.Count, 1).End(xlUp).Row For 処理業 = 1 To 最終行 For a = 1 To 5 b(a - 1) = Cells(1, 値列) 値列 = 値列 + 1 Next 値列 = 17 For a = 1 To (22 - 値列) c = c + b(a - 1) Next Cells(処理業, 30) = c a = 0 c = 0 Next 処理業 End Sub ただ計算する列の範囲をインプットボックスで入力した値 にしたい為以下のように改造しました。 Dim b(対象列) As Integerでエラーになります 配列には変数は使用できないのでしょうか? よろしくお願いします。 Sub 計算() '失敗 Dim a As Integer Dim c As Integer Dim b(対象列) As Integer’★ここでERRになる Dim 最終行 Dim 対象列 Dim 値列  対象列 = 22'インプットボックスで入力した値 値列 = 17 最終行 = Cells(Rows.Count, 1).End(xlUp).Row For 処理業 = 1 To 最終行 For a = 1 To (対象列 - 17) b(a - 1) = Cells(1, 値列) 値列 = 値列 + 1 Next 値列 = 17 For a = 1 To (22 - 値列) c = c + b(a - 1) Next Cells(処理業, 30) = c a = 0 c = 0 Next 処理業 End Sub

  • VBAのプログラムでうまく動かなくて困っています。

    VBA初心者です。 エクセルのVBAのプログラムでうまく動かなくて困っています。教えていただける方がいらしたら、ぜひ教えて下さい!よろしくお願いします。エクセルの内容は以下のとおりです。 (内容) セル    E H J L N P R・・・ 8行目100 200 50 40 30 80 9行目130 350 10 50 60 120 110 ・ ・ (1)列Hの値が列Eの値より大きい場合その下に行を追加します。 (2)セルJ+セルL+セルN+・・をしてセルEの値を超えたセル以降の値を追加した行のセルJ列から順にコピペする処理です。 上のセルの1行目の内容でいいますと、 (1)列Hの値「200」が列Eの値「100」より大きいのでその下に行追加 (2)セルJ、L、N「50」+「40」+「30」でセルEの値「100」より大きいので、追加した行のセルJ列にセルN、Pの値をコピペするです。 以下が私が書いたプログラムです。 Sub test() Dim x As Integer Dim s As Integer Dim t As Integer x = Range("B8").End(xlDown).Row r = Range("J8").End(xlToRight).Column '8行目から最終行までループ For i = x To 9 Step -1 If Cells(i, 5) < Cells(i, 8) Then ☆【For r = y To 11 Step -2 Cells(s, t).Value = Cells(i, r) + Cells(i, r + 2) If Cells(i, 5).Value < Cells(s, t).Value            Then Exit For Next】 Rows(i + 1).Insert Shift:=xlDown '超えたセルをコピーして、1行下の"J列以降"に代入 ★ x = x + 1 End If Next i End Sub 上記プログラムで★の部分がうまく書けません。☆の部分も間違っているような気がします。よろしくお願いします。

専門家に質問してみよう