あるクラスの算数の平均点と理科の平均点を読み込み 総点を計算するプログラムを考えてみましょう 一クラスだけ読み込む場合は test50 のようなプログラムになります プログラムの流れとしては非常に簡単です Sub test50() a = InputBox(" バナナ組の算数の平均点を入力してください ") b = InputBox(" バナナ組の理科の平均点を入力してください ") MsgBox " バナナ組の総点は " & a + b & " です " このプログラムは 1 つのクラスだけを対象にしていますが クラスが増えた場合にはどのようなプログラムになるでしょう 例えば バナナ メロン アップル オレンジ ピーチ組の全部に対して同様な操作を行う場合を考えます test51 がそのプログラムです Sub test51() a = InputBox(" バナナ組の算数の平均点を入力してください ") b = InputBox(" バナナ組の理科の平均点を入力してください ") MsgBox " バナナ組の総点は " & a + b & " です " a = InputBox(" メロン組の算数の平均点を入力してください ") b = InputBox(" メロン組の理科の平均点を入力してください ") MsgBox " メロン組の総点は " & a + b & " です " a = InputBox(" アップル組の算数の平均点を入力してください ") b = InputBox(" アップル組の理科の平均点を入力してください ") MsgBox " アップル組の総点は " & a + b & " です " a = InputBox(" オレンジ組の算数の平均点を入力してください ") b = InputBox(" オレンジ組の理科の平均点を入力してください ") MsgBox " オレンジ組の総点は " & a + b & " です " a = InputBox(" イチゴ組の算数の平均点を入力してください ") b = InputBox(" イチゴ組の理科の平均点を入力してください ") MsgBox " イチゴ組の総点は " & a + b & " です " a = InputBox(" ピーチ組の算数の平均点を入力してください ") b = InputBox(" ピーチ組の理科の平均点を入力してください ") MsgBox " ピーチ組の総点は " & a + b & " です "
このプログラムを見ると同じ操作ですが クラスの名前だけが違っています このような 同じ操作を繰り返す場合には操作をひとまとめにして別のプログラムとして独立させ それを呼び出すことで同じ計算ができます そのように書き換えたプログラムが test52 です test52 を実行してみると test51 と同じ動きをします Sub test52() Call proc53(" バナナ ") Call proc53(" メロン ") Call proc53(" アップル ") Call proc53(" オレンジ ") Call proc53(" ピーチ ") Call proc53(" レモン ") Sub proc53(fruts As String) a = InputBox(fruts & " 組の算数の平均点を入力してください ") b = InputBox(fruts & " 組の理科の平均点を入力してください ") MsgBox fruts & " 組の総点は " & a + b & " です " test52 はどのような動きをしているのでしょう test52 には単に Call proc53( xxx ) と書かれています Call という命令は別のところで定義されているプログラムを呼び出しなさいという命令です この場合には proc53 というプログラムを呼び出しています proc53 はすぐ下にあります proc53 はこれまでのプログラムの書き方と少し異なります どの点かというと これまでは () 内に何も書きませんでしたが このプログラムでは fruts as String とまるで変数の定義のような書き方がしてあります 実際にこれは変数の定義です fruts という文字変数を定義しています この fruts という変数に何が入るかというと test52 で記述されていたクラスの名前 ( フルーツ名 ) が入ります つまり このカッコ内の変数は呼び出す側から 呼び出される側へのデータの受け渡しに使われます このような変数を引数 ( ひきすう ) と呼びます fruts の部分を呼び出す際の変数に置き換えてみると test51 と同じ命令になります このようなプログラムの書き方は大きなプログラムを書く場合にしばしば使います 逆にこれまでのようにプログラム全体を 1 つのプログラム (Sub End sub) 内に書くことは稀です なぜなら プログラムが複雑になってくるとデータの流れをわかりやすく記述することが難しくなるためです そのため プルグラム全体の流れを主プログラムに書き そこから各部品 ( 副プロシージャ ) を呼び出す形式をとります これにより 主プログラム設計者は全体の流れだけを作り 副プロシージャ設計者は各機能プログラムを担当するこ
とで分担作業が可能になります これはまるで大きな製品を作る際の分業に似ています 例えば 車一台を作る場合でも各部品は多くの部品メーカーが作ります そして 車メーカーは最後の組み立て部分だけを行います 車メーカーは規格 仕様のデータを部品メーカーに渡すだけです 各部品メーカーは同じような部品であれば他社の車の部品もデータさへ揃えば作ることも可能です このように 分業化するだけでなく いろいろな場面で同じような操作を行うことがありますので 副プロシージャを用意しておけば様々な別のプログラムでも使うことができます 使い方は下記の通りです Call xxxxx( yyyy ) xxxxx という別のプロシージャを呼び出すその際に引数として yyyy というデータを引き渡す Sub xxxxx(zzzz As wwww) 呼び出された際に zzzz という変数に yyyy とい うデータが入る 次に a,b,c の数値を渡して 3 倍した値を計算する場合を考えてみます Sub proc54() Dim c As Double Dim x As Double Dim y As Double Dim z As Double a = 3# b = 5# c = 7# MsgBox "a=" & a & " b=" & b & " c=" & c MsgBox "x=" & x & " y=" & y & " z=" & z Call proc55(a, b, c, x, y, z) MsgBox "a=" & a & " b=" & b & " c=" & c MsgBox "x=" & x & " y=" & y & " z=" & z Sub proc55(d As Double, e As Double, f As Double, l As Double, m As Double, n As Double) MsgBox "proc55 では d=" & d & " e=" & e & " f=" & f MsgBox "proc55 では l=" & l & " m=" & m & " n=" & n l = 3 * d m = 3 * e n = 3 * f MsgBox "proc55 では d=" & d & " e=" & e & " f=" & f MsgBox "proc55 では l=" & l & " m=" & m & " n=" & n
Proc54 を実行すると下の順にメッセージボックスが現れます 上の 2 つは Call proc55(a,b,c,x,y,z) 実行前の変数の値を表示しています この段階では a,b,c には値を代入しましたが x,y,z には値を代入していませんので全部ゼロです 次にプログラムは Call proc55(a,b,c,x,y,z) の呼び出しにより 制御が proc55 へ移ります 上の 2 つのウィンドウは proc55 の最初の状態を表示しています proc54 で呼び出された前と同じ状態であり 適切に引数の受け渡しが行われていることがわかります 計算が行われた後のデータが上の 2 つのウィンドウです 最初はゼロであった l,m,n に d,e,f の 3 倍の値が代入されています この後に制御は proc54 へ戻ります 上の 2 つは proc54 へ戻った直後の状態です proc55 で設定された値が適切に引き渡されています 引数を用いてデータのやり取りを行う場合は呼び出す側 (proc54) と 呼び出される側 (proc55) で変数名が同じである必要はありません 変数の型が同じであれば引き渡しができます proc54 と proc55 では (a,b,c,x,y,z) がそれぞれ (d,e,f,l,m,n) に対応しています このように 引数を用いることでデータの受け渡しができます
引数には配列を指定することもできます その例が proc56 です Sub proc56() Dim daisho(100) As Integer Dim i As Integer For i = 1 To 10 daisho(i) = Cells(i, 1) Next i Call proc57(daisho()) For i = 1 To 10 Cells(i, 2) = daisho(i) Next i Sub proc57(daisho() As Integer) Dim k As Integer Dim j As Integer Dim temp As Integer For k = 1 To 9 For j = k + 1 To 10 If (daisho(k) > daisho(j)) Then temp = daisho(k) daisho(k) = daisho(j) daisho(j) = temp End If Next j Next k このプログラムはエクセルのシート上の A1 から A10 へ代入されている整数値を小さい順に並べ B1 から B10 へ出力するプログラムです このプログラムではデータの引き渡しに配列変数が使われています 呼び出す側では Call proc57(daisho()) と記述されています Call 文やサブプロジージャ名を記述する方法は同じですが引数の部分が少し 違っています 変数であればそのまま書けばよかったのですが 配列の場合には配列の () の部分に何も記載されていません これは配列全体を渡すことを意味しており この配列は最初にサイズを決めていますのでわざわざ指定する必要はありません また 呼び出される側でも daisho() と記載されており 配列の大きさは定義されていません これも呼び出し側で決めているのでここで記述する必要がないからです 引数によるデータの受け渡しは実際のデータをやりとしているのではなく 記憶されているメモリー上の位置を教え合っているだけです これにより 同じ位置でのデータを処理しています そのため 配列でもメモリー上の位置がわかれば型が同じですので呼び出し側と同じように扱うことができます
これまでの sub XXX() end sub のような独立したプログラムと同じような機能を持つもので Function プロシージャというものがあります これはまさに関数です 例えば VBA の組み込み関数 ( 標準で準備されている関数 ) の cos(3.1415926) と書くと-1 が示されます Function プロシージャというのはまさに関数で ユーザーが自由に作ることのできる関数です 特徴としては値を返すことができるという点で 呼び出し方は下記のようになります A=Function 名 ( 引数 ) 引数を渡して その結果が戻り値として A に代入されます proc58 を実行してみてください Sub proc58() Dim x As Single Dim a As Single Dim b As Single a = InputBox(" 数値を代入してください ") b = InputBox(" 数値を代入してください ") x = func59(a, b) MsgBox x Function func59(c As Single, d As Single) As Single func59 = c * d End Function このプログラムは 2 つの数値を入力してその積を計算します 積の計算の部分だけ Function プロシージャとして独立したプログラムになっています 呼び出し側はサブプロシージャとは異なり x=func59(a,b) と記述されており まるで func59 が数値のように書き表されています これは先に示した cos() 関数のような使い方です つまり 引数 a,b を使って func59 で計算された結果が x に代入されるという意味です つまり 呼び出し方は関数名を直接指定して サブプロシージャと同様に引数を使ってデータを渡します Function 側を見てみると記述の方法がサブプロシージャとは異なります まず 最初の定義が Function になっています そして 引数の記述方法は同じですが それに続いて As Single とまるで変数を定義するように記述されています 確かに 呼び出し側を見てみると変数のような使い方をされますので関数の戻り値の型を決める必要があります そのため このような定義になります そして もう一つ異なる点は func59=c*d の部分です 変数として func59 はどこにも定義されていません Function プロシージャの場合 プロシージャ名がそのまま変数になります そして 戻り値として返したい値をプロシージャ名と同じ変数へ代入することで自動的に値が返ります
別の変数に代入する形で呼び出しましたが 変数または数値と同じように扱うことも可能です Sub proc60() Dim a As Single Dim b As Single a = InputBox(" 数値を代入してください ") b = InputBox(" 数値を代入してください ") MsgBox func59(a, b) proc60 では別の関数である MsgBox の引数として func59 を直接指定しています 結果は先ほどと同じです このように Function プロシージャは値を一つだけ返すことができ 変数や数値そのものとして扱うことができるのでわざわざ別に変数を定義する必要がない点が特徴です 複数返すことはできませんのでサブプロシージャを使ってください サブプロシージャや Function プロシージャの呼び出しは何回でも可能でこれらからさらに別のサブプロシージャや Function プロシージャを呼び出すことが可能です ただし ループ化しないよう気を付けてください これらを用いることにより 複雑なプログラムの明確化ができ 更にはプロジェクトとして分担して作成することができるようになります