Выделение разыменованного указателя в Фортране - PullRequest
1 голос
/ 22 апреля 2020

Я пытаюсь создать массив указателей в Fortran 90, как описано здесь . Каждый указатель в этом массиве затем связывается с массивом чисел с плавающей запятой, который должен быть выделен во время выполнения путем разыменования указателя. См. Пример ниже:

program test
    type ptr
        double precision, pointer :: p(:)
    end type ptr

    integer :: i, n=5
    type(ptr), dimension(3) :: ptrs
    double precision, pointer :: a(:), b(:), c(:)

    ptrs(1)%p => a
    ptrs(2)%p => b
    ptrs(3)%p => c

    do i=1,3
        allocate(ptrs(i)%p(n))
        ptrs(i)%p = 0d0
    enddo

    write(6, *) ptrs(1)%p
    write(6, *) a

end program test

Результат:

$ gfortran -o test test.f90 && ./test                                                                                                 
0.0000000000000000        0.0000000000000000        0.0000000000000000        0.0000000000000000        0.0000000000000000
At line 20 of file test.f90 (unit = 6, file = 'stdout')
Internal Error: list_formatted_write(): Bad type

Ошибка выдается, потому что a не выделено. В идеальном мире ptrs(1)%p и a должны быть идентичны, но, очевидно, этот мир несовершенен. Мой вопрос: Как правильно распределить a, b и c?

Ответы [ 2 ]

2 голосов
/ 22 апреля 2020

Важно отметить, что при

allocate(ptrs(i)%p(n))

вы не выделяете (в соответствии с заголовком вопроса) указатель с разыменованным . То есть выделение не влияет на состояние назначения указателя. Вместо этого это распределение создает новую цель для ptrs(i)%p.

. В ответе, связанном с вопросом, целевые массивы сами по себе не являются указателями или размещаемыми объектами, они являются явными массивами форм. Это приводит к тонкому различию в том, какие подходы открыты для вас.

Если вы хотите использовать динамическую c связь с целями указателей компонентов, то вы можете указывать указатель на цель после цели сам по себе выделен. Что-то вроде:

allocate(a(n))
ptrs(1)%p => a

В качестве альтернативы, вы можете рассмотреть возможность использования только выделяемых компонентов:

type ptr
  double precision, allocatable :: p(:)
end type ptr
2 голосов
/ 22 апреля 2020

Я предлагаю всегда аннулировать ваши указатели. Таким образом, вы не сможете легко справиться с неопределенным поведением, вызванным неопределенными указателями.

С производным типом вы можете использовать инициализацию по умолчанию

type ptr
    double precision, pointer :: p(:) => null()
end type ptr

double precision, pointer :: a(:), b(:), c(:)

Указатель a указывает на какой-то неопределенный адрес мусора.

ptrs(1)%p => a

Теперь ptrs(1)%p указывает на тот же адрес мусора.

allocate(ptrs(i)%p(n))

Теперь назначена новая цель и ptrs(1)%p указывает там , a не затрагивается.

Вместо этого теперь вам нужно указать a и на этот новый адрес.

a => ptrs(1)%p

Важно не учитывать a и ptrs(1)%p быть двумя псевдонимами одного и того же. Они не. Оба указатели и оба указывают куда-то. Вы несете ответственность за то, чтобы они всегда указывали на один и тот же адрес.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...