2011-08-03 6 views
3

저는 Fortran 초보자입니다. 나는 주 프로그램에서 4 개의 인수를 취할 서브 루틴을 작성하려고하고 있는데, 처음에 전달 된 4 개의 인수가 포함 된 배열을 주 프로그램에 출력합니다.이 작업을 수행하는 좋은 방법은 무엇입니까?현명한 방법으로 Fortran 90에서 인수를 전달하십시오.

예를 들어, 아래에있는 내 테스트 프로그램에서, 나는 메인 프로그램에서 네 개의 실제 변수를 (a, b, cd)를 만듭니다. 그런 다음이 실제 변수를 mysub이라는 서브 루틴으로 전달합니다. mysuba, b, cd을 가져 와서 o이라는 2x2 배열을 채운 다음 o을 주 프로그램에 보내서 (그리고 가능한 수정이 가능함) 사용할 수 있습니다. 나는 다음과 같은 오류 얻을

SUBROUTINE mysub(w,x,y,z) 
    IMPLICIT NONE 
    REAL, INTENT(IN) :: w, x, y, z 
    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o 

    ALLOCATE(o(2,2)) 
    o(1,1)=w 
    o(1,2)=x 
    o(2,1)=y 
    o(2,2)=z 
END SUBROUTINE mysub 
END MODULE testsubs 

PROGRAM test 
    USE testsubs 
    IMPLICIT NONE 
    REAL :: a=1.1, b=2.2, c=3.3, d=4.4 

    CALL mysub(a, b, c, d) 

    PRINT *, o(1,1), o(1,2) 
    PRINT *, o(2,1), o(2,2) 
END PROGRAM test 

을 :하지만 그래서, 나는 다음과 같은 노력

test.f90:10.53: 

    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o 
                1 
Error: Symbol at (1) is not a DUMMY variable 

내가으로이 해석을 o이 아니므로, 컴파일러, o이 무엇인지 모르는 서브 루틴 헤더의 인수 목록 : SUBROUTINE mysub(w,x,y,z). 그래서 아마도 그 헤더에 o을 포함시켜야 할 것입니다. 그래서, 다음 (내가 !...을 사용하여 변경 또는 추가 사항을 표시 한) 다음과 같은 시도 :

SUBROUTINE mysub(w,x,y,z,o) !... 
    IMPLICIT NONE 
    REAL, INTENT(IN) :: w, x, y, z 
    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o 

    ALLOCATE(o(2,2)) 
    o(1,1)=w 
    o(1,2)=x 
    o(2,1)=y 
    o(2,2)=z 
END SUBROUTINE mysub 
END MODULE testsubs 

PROGRAM test 
    USE testsubs 
    IMPLICIT NONE 
    REAL :: a=1.1, b=2.2, c=3.3, d=4.4 
    REAL, DIMENSION(:,:), ALLOCATABLE :: o !... 

    CALL mysub(a, b, c, d, o) !... 

    PRINT *, o(1,1), o(1,2) 
    PRINT *, o(2,1), o(2,2) 
    DEALLOCATE(o) !... 
END PROGRAM test 

이 잘 작동하는 것 같다, 그리고 나는 올바른 출력을 얻을 :

1.1000000  2.2000000 
    3.3000000  4.4000001 

하지만, 내 질문에 이것이 좋은 방법인가요? 이 예제에서, 배열 o을 서브 프로그램의 의 메인 프로그램에 모두으로 선언하고 있습니다. 나는 이것이 내가 (오류 메시지를 피하기 위해,하지만 하지 모두, 내가 생각하는) 중 하나 서브 루틴 또는 주 프로그램이 o를 할당 알아서해야한다는 것을 의미한다고 생각하기 때문에, 혼동을 일으킬 것으로 보인다. 서브 루틴에서 메인 프로그램으로 배열을 전송하는 더 똑똑한 방법이 있습니까? 시간 내 주셔서 감사합니다. 당신은 배열을 반환하려는 경우

답변

3

해결 방법 "o"를 의도 (out) 인수로 사용하는 것이 좋습니다. "o"가 인수가되지 않으면 서브 루틴의 변수 "o"와 주 프로그램의 변수 "o"사이에 연결이 없으므로 주 프로그램에 선언 또는 할당이 없습니다. 또 다른 해결책은 (@ ja72가 제공하는 것 외에) 메소드를 변경하는 것입니다 : 서브 루틴의 의도 (inout)를 "o"로 만들고 메인 프로그램에 할당하십시오. 가능한 이점 : allocate와 deallocate가 코드에서 더 가깝고 쌍을 이룬다. 가능한 단점 : 프로그램 논리 및 설계에 따라 배열 크기가 서브 루틴에 가장 잘 알려져있을 수 있습니다.

P.주 프로그램에 배열을 할당하고 서브 루틴에서 배열의 할당 가능한 속성을 실제로 사용하지 않으면 (즉 할당하거나 할당을 해제하지 않은 경우) allocatable 속성을 사용하여 배열을 선언 할 필요가 없습니다 서브 루틴에서 - 유용한 단순화. 어떤 경우에는 "의도 (out)"가 적절할 수 있습니다. 그러나 메인 프로그램에 배열을 할당하고 해당 상태를 서브 루틴으로 전달하고자한다면 인수 상태는 "의도 (out)"가 될 수 없습니다. "의도 (out)"는 프로 시저에 입력 할 때 자동으로 인수를 할당 해제합니다.

1

당신은) 하위 내에서 할당하여 예 # 2 같은 INTENT(OUT)으로 인수에 추가 할 수 있습니다, 또는 b) 함수를 작성하고 외부 배열을 할당 :

FUNCTION myfun(w,x,y,z,n,m) 
IMPLICIT NONE 
INTEGER, INTENT(IN) :: n,m 
REAL, DIMENSION(n,m) :: myfun 
REAL, INTENT(IN) :: w,x,y,z 

    myfun(1,1)=w 
    myfun(1,2)=x 
    myfun(2,1)=y 
    myfun(2,2)=z 

END FUNCTION 
END MODULE testsubs 

PROGRAM test 
    USE testsubs 
    IMPLICIT NONE 
    REAL :: a=1.1, b=2.2, c=3.3, d=4.4 
    REAL, DIMENSION(:,:), ALLOCATABLE :: o !... 

    ALLOCATE(o(2,2)) 
    o = myfun(a,b,c,d,2,2) 

    PRINT *, o(1,1), o(1,2) 
    PRINT *, o(2,1), o(2,2) 
    DEALLOCATE(o) !... 
END PROGRAM test 

사실 나는 당신의 솔루션이 더 깨끗하다고 ​​생각합니다.

1

미리 배열의 크기를 알고 있는지 여부는 분명하지 않지만 그렇게 할 경우 대개 같은 위치에 배열을 할당하거나 할당을 해제하는 것이 좋습니다. 가능한 경우 컴파일러가 메모리를 할당하도록합니다.

내가 할 것입니다 방법 : 크기는 컴파일 타임에 알려져있다

  • 경우 : 는 메인 프로그램에서 배열을 선언 서브 루틴에 intent(out)를 사용합니다.

  • 크기가 런타임에만 알려진 경우 : 메인 프로그램에 할당 메인 프로그램의 서브 루틴 및 할당 해제에 intent(out)를 사용한다.

기능은 출력을 복사해야하기 때문에 작은 출력에 가장 적합합니다.

관련 문제