1.5.8 サブルーチンへのデータ引渡

引数によるデータの引渡では, 前述の配列の記憶順序を意識したテクニックがよく使われる. MATH1のIFALIB, RFALIB, VRALIBなどでは, 1次元配列の要素を飛び飛びに使うための引数(JXなど)が必ずある. これは, 多次元配列を同じサブルーチンまたは関数で処理するためのものである. これらのルーチンの動作を理解するために, 以下のプログラムを見て欲しい.

 

      REAL X(100)
      ......
      CALL SUM(X, 100, 1, XSUM)
      ......
      END

      SUBROUTINE SUM(X, N, JX, XSUM)
      REAL X(*)

      XSUM = 0.
      DO 100 I=1, JX*(N-1)+1, JX
        XSUM = XSUM + X(I)
  100 CONTINUE
      END
 

このサブルーチンは1次元配列Xの和を求めて, XSUMとして返すものである. この同じサブルーチンを2次元配列Y に対して

      REAL Y(10,10) 
      ........
      CALL SUM(Y(2,1), 10, 10, YSUM)
      ......
      END

という様に使うと サブルーチンSUMは, 以下のように2次元配列要素Y(2,1)を 先頭とする記憶領域を1次元配列Xに割り当てる.



Y(2,1) Y(3,1) $ \cdots $ Y(10,1) Y(1,2) Y(2,2) $ \cdots $ Y(10,2) Y(1,3) Y(2,3) $ \cdots $
X(1) X(2) $ \cdots $ X(9) X(10) X(11) $ \cdots $ X(19) X(20) X(21) $ \cdots $


その1次元配列Xの要素を10 (JX) 個おきに10個の和をとると, Y(2,1), Y(2,2), ..., Y(2,10) という具合に, 二次元配列 Yの第2添字についての和をとることになる.

ここで, サブルーチンの中では配列Xの長さはわからず, 単に, X(1)を先頭とする1つながりのデータとして扱われていることに 注意して欲しい. 配列がサブルーチンに渡されるとき, メインプログラムの配列の中身がサブルーチンの 配列の中身にコピーされるのではなく, メインプログラムの中の配列の番地だけが渡され, サブルーチンの方はその番地を基準に処理を行うのである. このようなことを意識してプログラムを書くと, 少ない引数で柔軟な処理が可能になる.

もう一つの応用例を紹介しよう.


      SUBROUTINE SUM2(X, IMAX, IX, JX, XSUM)
      REAL X(IMAX,JX)

      XSUM = 0. 
      DO 100 I=1,IX 
      DO 100 J=1,JY 
        XSUM = XSUM + X(I,J) 
  100 CONTINUE 
      END 

これは2次元配列X(I,J)の一部の和をとるものであるが, これを

 

      REAL X(102,102)
      ........
      CALL SUM2(X(2,2), 102, 100, 100, XSUM)
      ........

という具合に使うと, 102×102の2次元配列のデータのうち, 周辺を残して真中の 100×100の部分, すなわち, (2,2)-(101,101)を対角線とする部分の和をとることができる. MATH1のルーチンで, このような使い方を想定しているものはないが, GRPH2のコンターを描くルーチンなどで応用すると便利である.

なお, サブルーチンに渡すことのできる引数のなかに, 「手続き名」がある. これは, 他の引数と異なり「変数」ではないので, 動的な変更はできないが, これが指定できるおかげで, MATH1のVRFNA/VIFNAの様に, サブルーチンを呼ぶ際に使うべき関数を指定することが可能になる. この場合, 実引数に指定する手続き名は, サブルーチンを呼ぶ プログラムの中で EXTERNAL文またはINTRINSIC文により 手続き名であることを宣言しておかなければならない.