忍者ブログ
バイオインフォマティックス技術者試験、情報処理試験など、IT系の試験を基礎から勉強します。また、Javaなどプログラミングを勉強します。

【VBAスタンダード対策】配列の多様な宣言構造を攻略!

VBAの配列には、宣言時に要素数を固定する「静的配列」と、後からサイズを変更できる「動的配列」があります。それぞれの宣言文法と、インデックス(添字)の構造的な決まりを整理しましょう。

1. 問題:配列の宣言方法と要素数の関係

【 問題 】 下記のA~Dの宣言のうち、VBAの文法として誤っているもの、または実行時にエラーとなる可能性が高い構造はどれでしょうか?

A: Dim List(5) As String
B: Dim List() As Integer
C: Dim List(1 To 10) As Double
D: Dim List(X) As Variant ' ※Xは変数とする

① A:要素数が5つの静的配列として宣言されている
② B:後でReDimが必要な動的配列として正しく宣言されている
③ C:添字の下限を1、上限を10として正しく宣言されている
④ D:宣言時に変数を使ってサイズを指定することはできない

2. 正解:配列宣言の制約に関する正解

正解: ④ D(および ① の解釈)

3. 解説:静的と動的、それぞれの宣言ルール

VBAの配列構造において、最も注意すべきは「Dimによる宣言時に変数を使えるか」という点です。

[ 配列宣言の構造ルール図 ]

■ A:静的配列 Dim List(5)
実は要素数は 6つ です(0,1,2,3,4,5)。試験では「5」と書くと0番目を含めて6つになる構造がよく問われます。

■ B:動的配列 Dim List()
カッコの中を空にするのが動的配列の構造です。この時点ではメモリは確保されず、後で ReDim を使ってサイズを決定します。

■ C:範囲指定 Dim List(1 To 10)
「1から始まる」とはっきり指定する構造です。Option Base 1 を使わずに下限を固定できるため、実務で推奨される書き方です。

■ D:変数による指定 Dim List(X)
【重要】 Dimステートメントで要素数を指定する際、変数を使うことはできません。変数の値に応じてサイズを決めたい場合は、一度「B」の形で宣言し、その後 ReDim List(X) とする必要があります。

1. ここが試験に出る!: スタンダード試験では「静的配列の宣言に変数を使っていないか」「動的配列なのにカッコの中に数字を書いていないか」といった、DimとReDimの使い分けが厳格に問われます。
2. エンジニアの視点: Java 17などの言語では `int[] list = new int[x];` のように変数での初期化が当たり前ですが、VBAは「コンパイル時にサイズが決まるもの(Dim)」と「実行時に決まるもの(ReDim)」を構造的に区別しています。この「理系NEO」な厳密さを理解すると、メモリ管理のミスが減りますね。


4. まとめ

「Dimで変数は不可、サイズ変更はReDim」。この配列宣言のルールを守ることで、実行時のエラー(「定数式が必要です」など)を未然に防ぐことができます。配列もまた、宣言という「設計図」を正しく書くことで、初めて大量のデータを安全に格納する器として機能するのです。


PR

【VBAスタンダード対策】変数のスコープ(有効範囲)の構造を攻略!

変数は、宣言する場所によってその「見える範囲(スコープ)」が異なります。プロシージャの中で宣言する「プロシージャレベル変数」と、外で宣言する「モジュールレベル変数」の構造的違いを、実行結果から読み解きましょう。

1. 問題:同名の変数が存在する場合の実行結果

【 問題 】 下記のコードを実行して Main プロシージャを呼び出した際、メッセージボックスに表示される数値はいくつでしょうか?

Dim num As Integer ' --- (A) モジュールレベル変数

Sub Main()
    Dim num As Integer ' --- (B) プロシージャレベル変数
    num = 100
    ShowValue
End Sub

Sub ShowValue()
    MsgBox num
End Sub

① 0
② 100
③ エラーになる
④ どちらのnumか選択するダイアログが出る

2. 正解:変数のスコープと優先順位に関する正解

正解: ① 0

3. 解説:なぜ「100」ではなく「0」なのか?

この問題の核心は、「名前は同じでも、メモリ上では全く別の箱(構造)である」という点にあります。VBAでは、より狭い範囲(プロシージャ内)で宣言された変数がその中では優先されますが、他のプロシージャからはその中身は見えません。

[ 変数の階層構造図 ]

■ 標準モジュール全体のエリア
│ [箱A] num (モジュールレベル) -> 初期値 0

Sub Main()
│ │ [箱B] num (プロシージャレベル) -> 100 を代入
│ │ ※Main内では[箱B]が[箱A]を隠す(シャドウイング)
End Sub

Sub ShowValue()
│ │ MsgBox num -> このプロシージャからは[箱A]しか見えない!
End Sub

1. ここが試験に出る!: スタンダード試験では、このように「わざと変数の名前を重複させたコード」で、変数の寿命と有効範囲の理解度を試してきます。Main で代入した num = 100 は、あくまで Main の中だけで有効な「プロシージャレベル変数」に対する操作です。別のプロシージャである ShowValue は、モジュールの先頭で宣言され、初期化(0)されたままの「モジュールレベル変数」を参照するため、答えは 0 になります。
2. エンジニアの視点: Java 17などのフィールド変数とローカル変数の関係と同じ構造です。実務でこの構造的なミス(意図しない0の参照)を防ぐには、モジュールレベル変数には m_num のように接頭辞を付けるのが、デバッグの手間を減らす理系NEOな設計です。


4. まとめ

「自分に近い方の変数が優先されるが、プロシージャをまたけば見え方が変わる」。このスコープの構造を正しく把握することで、変数の値が予期せず変わったり、逆に反映されなかったりするバグを確実に防ぐことができます。減数分裂において各細胞が独自の役割を維持するように、VBAも変数の有効範囲を厳密に分離することで、プログラムの整合性を保つのです。


【VBAスタンダード対策】一括データを渡す「配列引数」の構造を攻略!

複数のデータをまとめた「配列」を別のプロシージャへ渡す際、VBAには「引数名の後ろにカッコを付ける」という独自の記述ルールがあります。また、配列の受け渡しには、通常の変数とは異なる構造上の大きな制約が存在します。

1. 問題:配列を引数として受け取る正確な記述

【 問題 】 文字列型の配列 names を引数として受け取り、その内容を処理するプロシージャ ProcessAll を定義したい。また、VBAの構造的制約として、**「配列を引数として渡す場合は、必ず参照渡し(ByRef)でなければならない」**というルールに従うものとする。空欄 ( A ) に入る正確な組み合わせはどれでしょうか?

Sub Main()
    Dim MyList(5) As String
    ' --- 配列にデータを格納する処理 ---
    Call ProcessAll(MyList)
End Sub

Sub ProcessAll(( A ))
    ' --- 配列をループで回す処理 ---
End Sub

① ByVal names As String()
② ByRef names() As String
③ ByVal names() As String
④ ByRef names As String

2. 正解:配列引数の宣言構造に関する正解

正解: ② ByRef names() As String

3. 解説:配列引数特有の「カッコ」と「ByRef」

VBAにおいて配列を引数に取る場合、引数名の後ろに**「中身が空のカッコ ()」**を記述することで、それが単一の変数ではなく配列であることを構造的に明示します。

[ 配列受け渡しの絶対ルール ]
カッコの配置names() のように、型名(String)の前ではなく、変数名の直後にカッコを置きます。
ByRefの強制:VBAの構造上、固定長配列(サイズが決まっている配列)を引数として渡す際は、ByVal(値渡し)を指定することはできません。必ず ByRef(参照渡し) である必要があります。

[ なぜ ③ ByVal は誤りなのか ]
構造的制約:配列はデータサイズが大きくなる可能性があるため、VBAではメモリ効率を考慮し、コピーを作成する ByVal での受け渡しを(Variant型に格納しない限り)認めていません。

1. ここが試験に出る!: スタンダード試験では、この「配列=カッコ付きのByRef」という組み合わせが正確に書けているかが問われます。特に、Javaなどの他言語の癖で String() names のように型側にカッコを付けてしまうミスに注意が必要です。
2. エンジニアの視点: Java 17などの現代的な言語では配列もオブジェクト参照として渡されるため、実質的にVBAの ByRef に近い挙動になります。VBAで「どうしても元の配列を壊したくない」場合は、呼び出す直前で別の配列にコピー(代入)してから渡すといった工夫が必要になります。理系NEOな設計としては、この「書き換えのリスク」を承知した上で、効率的なメモリアクセスを行う構造を意識することが大切です。


4. まとめ

「配列を渡すならカッコを付けてByRef」。この物理的な記述ルールをマスターすることで、大量のデータを扱うマクロの構造を正しく制御できます。減数分裂において大量の遺伝情報がセットで受け継がれるように、VBAも配列という構造体を使って、複雑な情報を一括で、かつ正確にリレーしていくのです。

【VBAスタンダード対策】引数の受け渡し「ByVal」と「ByRef」の文法を攻略!

引数をどのように受け取るかは、プロシージャ宣言の「カッコ内」で指定します。キーワードの配置場所と、何も記述しなかった場合にVBAがどのように解釈するかという構造的ルールを確認しましょう。

1. 問題:引数受け渡しの正確な宣言文法

【 問題 】 プロシージャ Calculate を定義する際、引数 num を「呼び出し元の値に影響を与えない値渡し」として、また引数 target を「VBAの既定である参照渡し」として正確に記述しているものはどれでしょうか?

① Sub Calculate(num ByVal As Integer, target ByRef As String)
② Sub Calculate(ByVal num As Integer, ByRef target As String)
③ Sub Calculate(As Integer ByVal num, As String ByRef target)
④ Sub Calculate(Value num As Integer, Reference target As String)

2. 正解:引数宣言の記述順序に関する正解

正解: ② Sub Calculate(ByVal num As Integer, ByRef target As String)

3. 解説:引数リストの物理的構造

VBAにおいて、引数の性質を決定するキーワード(ByVal / ByRef)は、必ず**「変数名の直前」**に配置するという構造的な決まりがあります。

[ 引数宣言の基本フォーマット ]
(キーワード) + (引数名) + As + (型名)

ByVal(値渡し):呼び出し元から「値のコピー」だけを受け取る。
ByRef(参照渡し):呼び出し元の「変数そのもの(参照)」を受け取る。

[ 構造上の重要なルール ]
省略時の挙動:キーワードを何も書かずに Sub Calculate(num As Integer) と書いた場合、VBAは構造的に ByRef(参照渡し) であるとみなします。この「省略=参照渡し」は試験の超頻出ポイントです。
配置のミス:①のように変数名と型の間にキーワードを挟むことはできません。

1. ここが試験に出る!: スタンダード試験では、あえてキーワードを省略したコードを提示し、「呼び出し元の変数が書き換わるかどうか」を判断させる問題が出ます。「何も書いていなければ ByRef(本物が書き換わる)」という構造的デフォルトを即座に思い出せるかが合格の決め手です。
2. エンジニアの視点: Java 17などの現代的な言語は、基本データ型は値渡し、オブジェクトは参照(のコピー)渡しと決まっていますが、VBAは個別の引数ごとに明示的に指定できる柔軟な構造を持っています。実務では「意図しない書き換え」という最も厄介なバグを防ぐため、すべての引数に ByVal を明示するスタイルが推奨されます。理系NEOな保守性を高めるためにも、構造を明示する癖をつけましょう。


4. まとめ

「キーワードは変数名の前、書かなければ ByRef」。この文法構造を正確に守ることで、データの「安全性」と「共有」を自在にコントロールできるようになります。減数分裂が情報の受け渡しを厳密に行うように、VBAも引数の宣言一つで、プログラム全体のデータの運命を決定づけるのです。


【VBAスタンダード対策】変数の運命を分ける「値渡し」と「参照渡し」を攻略!

【VBAスタンダード対策】変数の運命を分ける「値渡し」と「参照渡し」を攻略!

プロシージャに引数を渡す際、VBAには「変数のコピーを渡す方法」と「変数そのものの場所を教える方法」の2通りがあります。呼び出された側で値を書き換えたとき、呼び出し元の「元の変数」に影響が出るかどうかが最大の構造的違いです。

1. 問題:引数の受け渡しによる「元の値」の変化

【 問題 】 プロシージャ Main から Process を呼び出しました。Process 内で引数の値を書き換えた後、再び Main に戻ってメッセージを表示した際、**元の変数 num が書き換わってしまう(10から20に変わる)**のは、どのような受け渡し構造のときでしょうか?

Sub Main()
    Dim num As Integer : num = 10
    Call Process(num)         ' --- ここで呼び出し ---
    MsgBox num               ' --- 元の変数はどうなった? ---
End Sub

Sub Process(n As Integer)
    n = 20                   ' --- 呼び出された先で書き換え ---
End Sub

① 値渡し(ByVal):変数の「分身(コピー)」を渡している場合
② 参照渡し(ByRef):変数の「実体(メモリ上の住所)」を教えている場合
③ 直接渡し:変数をそのまま移動させている場合
④ 共有渡し:すべての変数をモジュールレベルで共有している場合

2. 正解:引数の受け渡し概念に関する正解

正解: ② 参照渡し(ByRef):変数の「実体」を教えている場合

3. 解説:データの「コピー」か「実体」か

引数の受け渡しには、構造的に「分身を渡す」のか「本物を共有する」のかという違いがあります。VBAの既定(デフォルト)は参照渡しであるため、意識せずに書くと呼び出し元の値が書き換わってしまう可能性があります。

[ データの受け渡し構造図 ]

■ 値渡し (ByVal = By Value)
[Main] num(10) --(コピーを送信)--> [Process] n(10)
[Process]で n=20 にしても、[Main]の num(10) は変化なし

■ 参照渡し (ByRef = By Reference)
[Main] num(10) --(住所を共有)--> [Process] n(←実体はnum)
[Process]で n=20 にすると、[Main]の num(10) も 20 に変わる

[ なぜこの違いが重要なのか ]
ByVal(値渡し):元のデータを壊したくない、安全に処理したい時に使います(使い捨てのコピー)。
ByRef(参照渡し):呼び出し先に複数の結果を書き込んでもらいたい時や、巨大なデータを効率よく扱いたい時に使います。

1. ここが試験に出る!: スタンダード試験では、コードの実行結果として「最後に表示される変数の値」を問う問題が頻出します。宣言部に ByVal があるかないかを見極め、呼び出し元の変数が「守られているか、書き換わっているか」を判定できるかが勝負の分かれ目です。
2. エンジニアの視点: Java 17などのオブジェクト型引数は、実質的に「参照の値渡し」という少し複雑な挙動をしますが、VBAの ByRef はもっと直接的な「変数そのもの」の共有です。不慮の書き換えバグを防ぐために、実務では「原則 ByVal で書き、理由がある時だけ ByRef を使う」のが理系NEOな堅牢な設計ですね。


4. まとめ

「分身のByVal、実体のByRef」。この概念を理解すれば、複雑なプロシージャ連携でもデータの流れを完全に見失わずに済みます。減数分裂が元の情報を維持しながら新しい細胞を作るように、VBAも適切な受け渡し構造を選ぶことで、データの正確性を保ちながら処理を繋いでいくのです。