2017-02-21 38 views
2
module shared 
!derived type target here 
integer, parameter :: nblock = 2 
integer, parameter :: xdim = 2 

TYPE block_info 
    INTEGER        :: il=10,jl=20,kl=30 
    REAL, ALLOCATABLE      :: x(:) 
END TYPE block_info 
TYPE(block_info), TARGET :: block(nblock) 

end module shared 


module point_to 
!point to subroutine here 
use shared 

REAL, POINTER :: x(:) 
integer  :: il,jl,kl 

contains 

subroutine set_current(n) 
    nullify(x) 
    il = block(n)%il 
    jl = block(n)%jl 
    kl = block(n)%kl 
    x => block(n)%x(0:xdim) 
end subroutine set_current 

end module point_to 


program main 

use shared 
use point_to 

!Iam allocating derived type target and initialize 
do i = 1, nblock 
    allocate(block(i)%x(0:xdim)) 
    do j = 0, xdim 
     block(i)%x(j) = dble(i)*dble(j) 
    enddo 
enddo 

!Iam pointing using set_current subroutine and print 
do i = 1, nblock 
    call set_current(i) 
    do j = 0, xdim 
     write(*,*) "i= ",i, "j= ",j, block(i)%x(j), x(j) 
    enddo 
enddo 


end program main 

對於上面的代碼,我得到以下輸出;0號指針有問題

i=   1 j=   0 0.00000000  0.00000000  
i=   1 j=   1 1.00000000  0.00000000  
i=   1 j=   2 2.00000000  1.00000000  
i=   2 j=   0 0.00000000  0.00000000  
i=   2 j=   1 2.00000000  0.00000000  
i=   2 j=   2 4.00000000  2.00000000 

我已經應用了x向量從1開始到xdim,我沒有錯誤。當第一個索引被選爲0時,問題就開始了。在上面的輸出中,最後兩個值必須相等。那麼問題在哪裏?

+0

您使用過標籤[tag:fortran90]。對於Fortran問題,始終使用標籤[tag:fortran]。您可以添加另一個標籤來區分版本。 *但是,您的代碼不是Fortran 90.原始Fortran 95中甚至不允許對派生類型的可分配組件,它是Fortran 2003的一項功能。所以你的代碼是Fortran 2003. –

回答

2

Vladimir F's answer解釋了問題的由來。然而,這個細節在這裏的問題中經常出現,所以值得強調幾件事情。

即使數組部分與數組中的所有元素匹配,數組部分也與整個數組不同。 block(n)%x是一個完整的數組; block(n)%x(0:xdim)是一個數組節(即使該數組組件有界限0xdim)。

爲什麼這種差異很重要?我們來看看指針賦值的規則。指針賦值語句

x => block(n)%x(0:xdim) 

是數據指針賦值之一。正如其他答案提到的那樣,邊界重新映射。也可以給出一個界限規範。

無論是那兩個案件發生在這裏,我會想出到後來,更多的,所以我們在的情況下(見2008年的Fortran,7.2.2.3)

如果bounds- spec-list出現,它指定下界;否則,每個維度的下限是應用於指針目標相應維度的內部函數LBOUND(13.7.90)的結果。

LBOUND的結果是,其中整個陣列/陣列部分區別是重要的(2008年的Fortran,90年7月13日):

如果陣列是整個陣列... LBOUND(ARRAY,DIM )的值等於ARRAY的下標DIM的下限。否則,結果值爲1

這意味着LBOUND(block(n)%x)有導致這種情況下0,但LBOUND(block(n)%x(0:xdim))有導致1始終。

所有手段

x => block(n)%x ! x has lower bound 0 
x => block(n)%x(0:xdim) ! x has lower bound 1 

現在,弗拉基米爾˚F提到界重新映射:

x(0:xdim) => block(n)%x(0:xdim) 

這就是說x具有所請求的上限和下限。這是相當合理的,但帶有幾個警告:

  • 一個必須小心重複的界限;左手尺寸必須至多有與右手尺寸相同數量的元素,如果數量較少,那麼它是一個較小的數組。
  • 右側必須是等級1或簡單連續。

所有這些條件成立,但這使得泛化需要謹慎。

最後的話,有一個界限規格:

x(0:) => block(n)%x(0:xdim) 

這仍然規定了下限,但指針和目標始終具有相同的大小,而且也沒有限制秩/連續性。

總結:使用x => block(n)%x爲這個問題的簡單情況。

+0

謝謝你先生這麼好的解釋,現在都清楚了 – atelcikti1

1

首先,當您遇到問題時,請使用您的編譯器具有的所有調試功能,僅僅查看代碼是不夠的。

例如:

> gfortran -g -fbacktrace -fcheck=all -Wall zeroptr.f90 
zeroptr.f90:44.24: 

     block(i)%x(j) = dble(i)*dble(j) 
         1 
Warning: Possible change of value in conversion from REAL(8) to REAL(4) at (1) 
> ./a.out 
At line 52 of file zeroptr.f90 
Fortran runtime error: Index '0' of dimension 1 of array 'x' below lower bound of 1 

Error termination. Backtrace: 
#0 0x7fa2d4af3607 in ??? 
#1 0x7fa2d4af4115 in ??? 
#2 0x7fa2d4af44ba in ??? 
#3 0x4014dc in MAIN__ 
     at /home/lada/f/testy/stackoverflow/zeroptr.f90:52 
#4 0x401640 in main 
     at /home/lada/f/testy/stackoverflow/zeroptr.f90:37 

編譯器會告訴你直接錯誤所在。數組x從元素1開始,並且您試圖訪問元素0,因此您超出範圍。它發生在線52是

write(*,*) "i= ",i, "j= ",j, block(i)%x(j), x(j) 

爲什麼這樣呢?由於

x => block(n)%x(0:xdim) 

使得x指向block(n)%x(0:xdim),但x會從1開始!

在2003 Fortran語言,你可以做到這一點(指針重映射):

x(0:xdim) => block(n)%x(0:xdim) 

和它的作品如預期,但更好的只是使用block(n)%x

+0

設置x(0:xdim)=> block(n)%x(0:xdim)解決了我的問題。非常感謝。 – atelcikti1

+0

順便說一句,我使用GNU Fortran(Ubuntu 4.8.4-2ubuntu1〜14.04.3)4.8.4版本,但調試選項不像你說的那樣工作,沒有給出錯誤。這可能如何發生?再次感謝你。 – atelcikti1

+0

我的版本是4.8.5,所以它應該如我所示。當您運行編譯用於調試的代碼時,會顯示錯誤! –