2017-02-21 24 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]. Всегда используйте тег [tag: fortran] для вопросов Fortran. Вы можете добавить еще один тег, чтобы отличить версию. * Однако *, ваш код не является Fortran 90. Выделенные компоненты для производных типов даже не разрешены в оригинальном Fortran 95, это функция Fortran 2003. Таким образом, ваш код - Fortran 2003. –

ответ

2

Vladimir F's answer объясняет возникновение проблемы. Однако эта деталь очень часто возникает в вопросах здесь, поэтому стоит подчеркнуть пару вещей.

Раздел массива, даже если он соответствует всем элементам массива, - это не то же самое, что весь массив. block(n)%x - это целый массив; block(n)%x(0:xdim) - это раздел массива (даже если этот компонент массива имеет границы 0 и xdim).

Почему эта разница имеет значение? Давайте рассмотрим правила назначения указателя. Оператор присваивания указателя

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

является одним из назначений указателя данных. Как упоминается в этом другом ответе, существует такая вещь, как переопределение границ. Также можно дать спецификацию границ.

Ни один из этих двух случаев происходит здесь, и я пойду на что более позднее, так что мы в случае (см Fortran 2008, 7.2.2.3)

Если bounds- появляется спецификатор, он определяет нижние границы; в противном случае нижняя граница каждой размерности является результатом внутренней функции LBOUND (13.7.90), примененной к соответствующему размеру цели указателя.

Результат LBOUND где вся секция массива/массив различие имеет важное значение (Fortran 2008, 13.7.90):

Если ARRAY целый массив ... LBOUND (ARRAY, DIM) имеет значение, равное нижней границе для индекса 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!

В Fortran 2003 вы можете сделать это (указатель переназначения):

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, поэтому она должна работать, как я показал. Ошибка отображается при запуске кода, скомпилированного для отладки! –