2016-12-30 10 views
1

私はFortranプログラミングが初めてで、サブルーチン間の呼び出しを理解しようとしています。だから私はここでそれをサブルーチン間の呼び出し

をテストするための簡単なプログラムを書いた私のコードは

program dummy 

    real, allocatable, dimension(:)   :: zz,yy 

    call test2(zz,yy) 

    print *, zz, yy 

contains 

    subroutine test1(ar1,ar2,arsum) 
     real, dimension(:)     :: ar1,ar2 
     real, allocatable, dimension(:)  :: arsum 
     allocate(arsum(size(ar1)+size(ar2))) 
     arsum(1:size(ar1)) = ar1 
     arsum(size(ar1)+1:size(ar1)+size(ar2)) = ar2 

    end subroutine test1 

    subroutine test2(sg1,sg2) 
     real, dimension(3)    :: g1,g3 
     real, dimension(4)    :: g2,g4 
     real, allocatable,dimension(:) :: sg1,sg2,dum 
     g1 = 1.0 
     g2 = 2.0 
     g3 = 3.0 
     g4 = 4.0 
     call test1(g1,g3,dum) 
     sg1 = 2*dum 
     call test1(g2,g4,dum) 
     sg2 = 3*dum 
    end subroutine test2 

end program dummy 

あるしかし、これは、次のエラー

forrtl: severe (151): allocatable array is already allocated 
Image    PC    Routine   Line  Source    
dummy.exe   0000000000409B1C Unknown    Unknown Unknown 
dummy.exe   0000000000402E70 MAIN__      26 dummy.f90 
dummy.exe   0000000000402A2E Unknown    Unknown Unknown 
libc-2.23.so  00002B3E716C7830 __libc_start_main  Unknown Unknown 
dummy.exe   0000000000402929 Unknown    Unknown Unknown 

test1サブルーチンは、単に任意の与えられた二つの配列を連結し、私をスローします。 Test2サブルーチンは、連結される配列を定義し、出力に対して代数を行い、それらを新しい配列に格納します。プログラムdummyは単に新しい配列を出力します。

私はここで間違っているのですか?

答えて

3

プログラムの流れを見てみましょう。ここにはいくつかの用語が含まれていますが、使用されているものは、うまくいけば他のドキュメントを通して探求することができます。

メインプログラムは、サブルーチンtest2をいくつかの引数で呼び出します。ここでの問題については、これらの議論は興味深いものではない。代わりに、ローカル(サブルーチンへの)変数dumを見てください。

は、割り当て可能な配列です。 test2の実行時には起動されません。これはtest1以降の呼び出しに対する(実際の)引数で、test1の別の呼び出しに対する(実際の)引数です。だから、何がうまくいかない?

ここでは議論の意図が重要です。本当に重要です。この回答を続ける前に、別の場所で意図を読み取る必要があります。

ここで、引数のインテントについてよく知っています。

サブルーチンtest1を入力すると、仮引数のarsumは、実際の引数dumと同じ割り当て状態になります。 test1の実行中にallocateステートメントがあります。

allocateステートメントは、割り当てられていないものの割り当てを試みることがあります。これは、最初の呼び出しでは問題ありません。エントリdum/arsumに割り当てられていません。サブルーチンの実行中にarsumが割り当てられ、これはtest2の割り振り状態dumに影響します。

dumが割り当てられているため、test1への2回目の呼び出しでarsumが割り当てられました。 allocateステートメントが失敗し、このためにエラーメッセージが表示されます。

これは問題です。直し方? arsumが割り当てられていないことを確認する必要があります。そこ2つの自明の方法である:

  • 試験arsumの割り当て状況はと(おそらくdeallocateで)に応じて応答します。
  • test1の呼び出しの間にdumを割り当て解除します。

しかし、おそらくより適切な方法があります。 dumは、ある操作の値をtest2に戻すときにのみ有効です。意向に戻って考えてください:これはintent(out)の意味です。

我々はintent(out)のため、それがエントリに割り当てられている場合/ dumarsumが自動的に解放された属性test1、その後、

subroutine test1(ar1,ar2,arsum) 
    real, dimension(:)       :: ar1,ar2 
    real, allocatable, dimension(:), intent(out) :: arsum 
    allocate(arsum(size(ar1)+size(ar2))) 
    arsum(1:size(ar1)) = ar1 
    arsum(size(ar1)+1:size(ar1)+size(ar2)) = ar2 
end subroutine test1 

としてサブルーチンに書き換える場合。

最後に(図示せず)、関数を使用してarsumを返したり、割り当て可能な配列ではなく自動配列を使用することも考えられます。あるいは、Fortran 2003の自動割り当てと配列コンストラクタでさえ、

subroutine test1(ar1,ar2,arsum) 
    real, dimension(:)    :: ar1,ar2 
    real, allocatable, dimension(:) :: arsum ! Or with `intent(out)` 
    arsum = [ar1,ar2] 
end subroutine test1 
関連する問題