第7講 Subプロシージャ

第5話 Subプロシージャを利用した重複チェックソフトの改良

前話解答例
Public Class Form1
   Dim a(4, 4) As Integer, b(24) As Integer, s As Integer
   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
     '変数の宣言
     Dim i As Integer, w As String
     s = 0 '総数カウンタの初期化
     f1() 'ランダム行列の作成
     f2() '行列内の数字の重複の検査
     If s = 0 Then w = "数字の重複がありませんでした。"
     If s > 0 Then
       w = "数字の重複がありました。" + vbNewLine + "その数字は" + vbNewLine
       For i = 0 To s - 1
         w = w + b(i).ToString + " "
       Next
     End If
     Label2.Text = w
   End Sub

   Sub f1()
     '変数の宣言
     Dim i As Integer, j As Integer
     Dim w As String

     'ランダム行列の発生
     For i = 0 To 4
       For j = 0 To 4
         a(i, j) = Int(300 * Rnd())  '300は好みで調整
       Next
     Next
     'ランダム行列の表示
     For i = 0 To 4
       For j = 0 To 4
         If a(i, j) < 10 Then w = w + "00" + a(i, j).ToString + " "
         If a(i, j) >= 10 And a(i, j) < 100 Then w = w + "0" + a(i, j).ToString + " "
         If a(i, j) >= 100 Then w = w + a(i, j).ToString + " "
       Next
       w = w + vbNewLine
     Next
     Label1.Text = w
   End Sub

   Sub f2()
     '変数の宣言
     Dim i As Integer, j As Integer

     '重複検査 比べる側
     For i = 0 To 4
       For j = 0 To 4
         f3(i, j)
       Next
     Next
   End Sub

   Sub f3(ByVal p As Integer, ByVal q As Integer)
     '変数の宣言
     Dim i As Integer, j As Integer

     '重複検査  比べられる側
     For i = 0 To 4
       For j = 0 To 4
         If p <> i Or q <> j Then
           If a(p, q) = a(i, j) Then
             b(s) = a(i, j)
             s = s + 1
           End If
         End If
       Next
     Next
   End Sub

End Class

実行例


解説
今回のコーティング例では、継続判定条件のグローバル変数hが削られている。
重複があろうとなかろうと、ループは最後まで行うからです。
Private Sub Button1_Clickの最後に、結果を表示させていますが、
継続判定条件hがなくても、総数を数える変数(これをカウンタ変数という)sが用意されているので、
s = 0でしたら、"数字の重複がありませんでした。"と
s = 1でしたら、"数字の重複がありました。"と判定できるわけです。

+ vbNewLineは& vbNewLineでも同じです。これは改行を意味します。

前回は、Label2.Text = "数字の重複がありました。"のように直接表示させましたが、
今回はString型変数wを用意して、wを使って表示させています。
それは、
     If s > 0 Then
       w = "数字の重複がありました。" + vbNewLine + "その数字は" + vbNewLine
       For i = 0 To s - 1
         w = w + b(i).ToString + " "
       Next
     End If
のおいて、重複している数字が加えられていくからです。
ここのFor文の終わりがs - 1になっていることに注目して下さい。
理由は、
           If a(p, q) = a(i, j) Then
             b(s) = a(i, j)
             s = s + 1
           End If
後からのカウントになっているからです。もし、ここが
           If a(p, q) = a(i, j) Then
             s = s + 1
             b(s) = a(i, j)
           End If
と前カウントとなっていれば
       For i = 1 To s
         w = w + b(i).ToString + " "
       Next
としなければなりません。ただし、これだと配列変数b(0)が1回も利用されません。
したがって、メモリを無駄にしないという点では後カウントの方が優れています。

尚、配列b(24)はグローバル配列でなければなりません。
f3のローカル配列だと、f3が終了して消滅と同時にローカル配列も消滅してしまうからです。
プロシージャは、呼び出されたときのみメモリに存在し、終了と同時にメモリから消えるようになっているのです。
C言語では、これを動的関数と呼びます。
VBのプロシージャも動的です。
動的という意味は、生成消滅を繰り返すという意味です。
今回のf3は、25回の生成消滅を経験します。
比べる側から25回呼び出されるからです。
それに対して、1回しか呼び出されない比べる側f2は1回だけ生成消滅を体験します。
f1も1回しか呼び出されませんので、1回だけ生成消滅をします。
注意しなければならない点は、f3が活動しているとき、
Private Sub Button1_Clickとf2は、活動が一時中断しているとはいえ、メモリ上に生きています。
このとき、コード上にあるプロシージャで、死滅してしまっているはf1だけです。
コンピュータは、上から下へと直線的に処理をしていきます。
ですから、f3の活動が終了するまで、f2は動きがとれませんので待機しているのです。
呼び出された側は、呼び出されたときのみメモリ上に存在して生きていますが、
呼び出す側は、呼び出された側が終了するまで待機して生を継続しています。


実行画面からおわかりになりますように同じ数字が2回出てきます。
これは、例えば179が比べる側と比べられる側の2回の役割を演じるからです。
左側の実行例においては、179は2つしかないので2回出てくるだけで済みます。
ところが、同じ数字3回出てくると、
6回も出場してしまいます。
それぞれの10が比べる側とくれべられる側の2役を演じてしまいますので、、
3×2=6個出てきてしまいます。
これは明らかな欠陥です。
これを改善するためにはどうしたらよいでしょうか。
つまり、重複チェックを重複してチェックしてしまうことを如何に改善するかということです。
これは大変な難問です。
解答例は次話で。


第4話へ 第6話へ

006

VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座

数学研究室に戻る