Lesson 12 - Sub プロシージャ

同じ内容の操作を何度も行ったり,1つのことをするのに長いプログラムが必要な場合は,その内容をひとまとめにすることが出来れば,楽ですしバグの発生する可能性も下がります。

次の例を見てみましょう。

#prompt
Dim T As String
Dim i As Double, n As Double, v As Double, s As Double

Print "平均値を求めます。"

Do
    Print "データ件数";
    Input T
    v=Val(T)
Loop Until v>0 ' 件数が0以下の場合は入力し直し

n=v
s=0
For i=1 To n
    Do
        Print Str$(i)+"人目のデータ";
        Input T
        v=Val(T)
    Loop Until v>0 ' データの値が0以下の場合は入力し直し
    s=s+v
Next

Print "平均値は"; s/n; "です。"
平均値を求めます。
データ件数? -4
データ件数? 3
1人目のデータ? 1.2
2人目のデータ? -3.0
2人目のデータ? 0
2人目のデータ? 1.8
3人目のデータ? 1.6
平均値は 1.53333333333333 です。

この場合,「データ件数を入力する部分」と「データの値を入力する部分」が共通ですね。(実際はもっと簡潔に書ける部分もあるのですが,少し直してあえて共通にしているのです(爆)。)
そういうところを1つにまとめるのが,今回のテーマである「プロシージャ」の働きなのです。

プロシージャとは,いくつかの処理を1つのブロックにまとめ,それを1つの操作として扱うためのものです。そのうち,単に処理のみを定義するものがSubプロシージャなのです。

下のプログラムは,上のものをSubプロシージャを使って書き直したものです。

#prompt
Dim T As String
Dim i As Double, n As Double, v As Double, s As Double

Print "平均値を求めます。"

InputNumber("データ件数")

n=v
s=0
For i=1 To n
    InputNumber(Str$(i)+"人目のデータ")
    s=s+v
Next

Print "平均値は"; s/n; "です。"

Sub InputNumber(Message As String)
    Do
        Print Message;
        Input T
        v=Val(T)
    Loop Until v>0
End Sub

後ろに書いた「Sub InputNumber」がポイントになります。
Sub [プロシージャ名] 〜 End Subの部分でプロシージャが行う内容を定義します。
この際,プロシージャの後ろのカッコの中に変数の宣言が入っていますが,これは関数のときと同様プロシージャの引数と呼びます。

このとき注意すべきなのは,プロシージャの引数の変数名はプロシージャの内部だけで有効ということです。
例えば,以下のコードを見て下さい。

#prompt
Dim T As String
Dim i As Double, n As Double, v As Double, s As Double

Print "平均値を求めます。"

InputNumber("データ件数")

' InputNumber プロシージャの中の変数の値を取得しようとしているが・・・
Print "メッセージ:"; Message

n=v
s=0
For i=1 To n
    InputNumber(Str$(i)+"人目のデータ")
    s=s+v
Next

Print "平均値は"; s/n; "です。"

Sub InputNumber(Message As String)
    Do
        Print Message;
        Input T
        v=Val(T)
    Loop Until v>0
End Sub

これをコンパイルしても,「"Message" 無効な識別子です」となって失敗します。つまりMessageという変数はInputNumberプロシージャの中でのみ有効なのです。

なお,同様にプロシージャの中でDim文を用いて変数を宣言すると,その変数はプロシージャの中だけで有効となります。
ですので,普通同じ名前の変数は重複して宣言できないのですが,下のプログラムは問題はありません。

#prompt
Print1(10)
Print2(5)
Print3(4)

Sub Print1(n As Long) ' 指定回数「1」を表示するプロシージャ
    Dim i As Long
    For i=1 To n
        Print 1;
    Next
End Sub

Sub Print2(n As Long) ' 指定回数「2」を表示するプロシージャ
    Dim i As Long
    For i=1 To n
        Print 2;
    Next
End Sub

Sub Print3(n As Long) ' 指定回数「3」を表示するプロシージャ
    Dim i As Long
    For i=1 To n
        Print 3;
    Next
End Sub

(実行結果)

1111111111222223333

問23
(1)正の整数 n を指定すると,それに対して 1+2+・・・+ n の値を計算して表示するSubプロシージャを作成せよ。
(2)そのプロシージャを,nを1から10まで変化させて呼び出せ。(注:プロシージャの内容を実行することを「呼び出す」と言うことがある。)


上の2つの例では,引数はどちらも1つでしたが,0個,または2つ以上でもよいです。
プロシージャを定義する側も呼び出す側も,引数がない場合は空のかっこを付け,2つ以上を指定する際は変数を「,」で区切ります(以下の例を参照)。

' 九九の表
#prompt
Dim i As Long, j As Long
For i=1 To 9
    For j=1 To 9
        PrintDigit(i*j, 3) ' 引数が2つのプロシージャの呼び出し方
    Next
    ToNextLine() ' 引数のないプロシージャの呼び出し方
Next

' 次の行に進むプロシージャ
'(プロシージャ化するほどでもないのですが・・・説明のため)
Sub ToNextLine()
    Print ' Print文で何も指定しないと,改行するのみ
End Sub

' 桁数を揃えて表示するプロシージャ
Sub PrintDigit(number As Long, digit As Long)
    Dim i As Long ' プロシージャの外と重複で「i」を宣言しているが大丈夫。(前述)
    i=Int(Log(number)/Log(10)+1) ' 桁数を求める(注)
    If i<digit Then
        Print String$(digit-i, " "); ' 足りない桁数を埋めるスペースを入れる
    End If
    Print number; ' 元の値を表示する
End Sub

実行結果

  1  2  3  4  5  6  7  8  9
  2  4  6  8 10 12 14 16 18
  3  6  9 12 15 18 21 24 27
  4  8 12 16 20 24 28 32 36
  5 10 15 20 25 30 35 40 45
  6 12 18 24 30 36 42 48 54
  7 14 21 28 35 42 49 56 63
  8 16 24 32 40 48 56 64 72
  9 18 27 36 45 54 63 72 81

(注)log10n は以下のように変化する。つまり桁数より1少ない値が出る。(logについては「指数関数の基本」を参照)

n 1・・・10・・・100・・・1000・・・
log10n 0・・・1・・・2・・・3・・・

問24
3つの数値を指定し,以下のように処理を行うSubプロシージャ「Compare_Three」を作成せよ。
(1)1番目の引数の値が,2番目のもの以上でかつ3番目のもの以上であるときは,「1番目が最も大きい」と表示する。
(2)2番目の引数の値が3番目のもの以上であるときは,「2番目が最も大きい」と表示する。
それ以外の場合は「3番目が最も大きい」と表示する。

#prompt
Compare_Three(1, 5, 7) ' 「3番目が最も大きい」が表示される
Compare_Three(6, 3, 2) ' 「1番目が最も大きい」が表示される
Compare_Three(-1, 8, 6) ' 「2番目が最も大きい」が表示される
Compare_Three(4, 4, 2) ' 「1番目が最も大きい」が表示される
Compare_Three(7, 2, 7) ' 「1番目が最も大きい」が表示される
Compare_Three(3, 9, 9) ' 「2番目が最も大きい」が表示される
Compare_Three(8, 8, 8) ' 「1番目が最も大きい」が表示される

' 以下にCompare_Threeプロシージャの定義を書く(問題)
 

戻る