Excel VBA | 配列の「範囲外アクセス」

VBA
スポンサーリンク

Excel VBAの配列とインデックス範囲の基本

不安なまま動かすより、仕組みを一度つかむと一気に楽になります。ここでは、配列の「インデックス範囲」と「実行時エラー」を、初心者でも迷わないように例題つきで説明します。


配列とは何か

  • イメージ: 配列は「番号つきの引き出し」。0番、1番、2番…と並んだ小さな入れ物に、同じ種類のデータを並べて入れます。
  • インデックス: 引き出しの番号のこと。VBAでは基本的に0から始まります(設定次第で1開始も可能ですが、初心者は0開始で覚えるのが安全)。

宣言とインデックス範囲のルール

  • 最大インデックスで宣言:
    Dim a(2) As String と書くと、使える番号は「0〜2」。つまり3個ぶんの引き出しです。
  • 範囲外はエラー:
    存在しない番号(例: 3)を使うと、プログラムを実行した時点で「実行時エラー」になります。書いた瞬間(コンパイル時)には気づけないので、動かして初めてエラーに気づくことが多いです。

まずは動かしてみる例題

例題1:正しい範囲で値を入れて取り出す

Sub Example1()
    Dim pref(2) As String  ' 0~2の3つ分

    pref(0) = "東京"
    pref(1) = "大阪"
    pref(2) = "福岡"

    Debug.Print pref(0)    ' → 東京
    Debug.Print pref(1)    ' → 大阪
    Debug.Print pref(2)    ' → 福岡
End Sub
VB
  • ポイント: Dim pref(2) は「3個使える」の意味。0、1、2の3つだけ。

例題2:範囲外でエラーが出る流れ

Sub Example2()
    Dim pref(2) As String  ' 0~2

    pref(0) = "東京"
    pref(1) = "大阪"
    pref(2) = "福岡"

    ' 次の行で実行時エラー(添字が範囲外)
    pref(3) = "札幌"
End Sub
VB
  • ここが落とし穴: コードの見た目は正しくても、実行した瞬間に「範囲外アクセス」で止まります。

よくある間違いと対策

  • 間違い: 「3つ入れたいから Dim a(3) だよね?」
    対策: VBAは0開始なので、3つなら Dim a(2)。4つなら Dim a(3)
  • 間違い: ループで範囲を1つ多く回す
Dim a(2) As Long
Dim i As Long
For i = 0 To 3  ' ← 3まで回すのはダメ(0~2が正しい)
    a(i) = i
Next i
VB

対策: For i = 0 To UBound(a) のように、配列の「上限」を取り出して使う。

Dim a(2) As Long
Dim i As Long
For i = LBound(a) To UBound(a) ' LBound=0, UBound=2
    a(i) = i
Next i
VB

安全に書くための基本テクニック

  • 要素数に依存しないループを書く
Dim nums(3) As Long  ' 0~3の4つ
Dim i As Long

For i = LBound(nums) To UBound(nums)
    nums(i) = i * 10
Next i
VB
  • 範囲チェックを入れる(防御的)
Sub SafeSet(ByRef arr() As String, ByVal idx As Long, ByVal value As String)
    If idx < LBound(arr) Or idx > UBound(arr) Then
        MsgBox "インデックスが範囲外です: " & idx
        Exit Sub
    End If
    arr(idx) = value
End Sub
VB

要素数を後から変える(ReDimの基礎)

  • 固定配列: Dim a(2) のように最初から個数固定。
  • 可変配列: まず「配列だけ」宣言し、あとで大きさを決められる。
Sub ExampleReDim()
    Dim items() As String   ' まだ大きさを決めない

    ReDim items(1)          ' 0~1(2個)
    items(0) = "A"
    items(1) = "B"

    ' もっと必要になったらサイズ変更
    ReDim items(3)          ' 0~3(4個)に作り直し
    ' ここで A, B は消える(再作成のため)
End Sub
VB
  • 値を保持したまま拡張したい: Preserve を使う ReDim Preserve items(3) ' 既存の中身を保持してサイズだけ拡張
  • 注意点: Preserve を使うと「最終次元」しか大きさを変えられません(多次元配列のときの制約)。

使いどころをイメージする例題

例題3:ユーザー入力数に合わせて可変配列に格納

Sub CollectNames()
    Dim count As Long
    Dim names() As String
    Dim i As Long

    count = CLng(InputBox("人数を入力してください(例: 3)"))
    If count <= 0 Then
        MsgBox "1以上の数を入力してください。"
        Exit Sub
    End If

    ReDim names(count - 1)  ' 0~(count-1)でcount人分
    
    For i = 0 To UBound(names)
        names(i) = InputBox((i + 1) & "人目の名前を入力")
    Next i

    Debug.Print "人数:", count
    For i = LBound(names) To UBound(names)
        Debug.Print i, names(i)
    Next i
End Sub
VB
  • ポイント: 入力人数に合わせて配列のサイズを決める。範囲は常に 0~count-1

まとめ(迷ったらここだけ見返す)

  • 配列の基本: 宣言の数字は「最大インデックス」。要素数は「最大インデックス+1」。
  • 範囲外は実行時エラー: 書いているときは気づけない。動かして初めて止まる。
  • 安全策: LBoundUBound を使ってループ範囲を自動化する。
  • 柔軟性: 可変配列は Dim arr()ReDim。中身を残すなら ReDim Preserve

次の一歩

  • Label: 反復処理に慣れる
    • ForDo While と配列の組み合わせを練習。
  • Label: エラーを恐れない
    • 範囲外に当たったら「学びポイント」。UBound/LBound で直せるか確認。
  • Label: 実践ミニ課題
    • 「5教科の点数を配列に入れて平均を出す」プログラムを書いてみる。
    • 可変配列で「入力数ぶんの合計と最大値」を出してみる。
タイトルとURLをコピーしました