Reputation: 2038
I am trying to create an array of pointers in Fortran 90, as described here. Each pointer in this array is then associated with an array of floats, to be allocated at run time by dereferencing the pointer. See the below example:
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
Result:
$ 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
The error is thrown because a
is not allocated. In an ideal world, ptrs(1)%p
and a
should be identical, but apparently this world is flawed. My question: How do I correctly allocate a
, b
, and c
?
Upvotes: 2
Views: 219
Reputation: 32451
The important thing to note here is that with
allocate(ptrs(i)%p(n))
you are not allocating (according to the question title) a dereferenced pointer. That is, the allocation does not affect the pointer's target allocation status. Instead, this allocation creates a new target for ptrs(i)%p
.
In the answer linked from the question, the target arrays are not themselves pointer or allocatable objects, they are explicit shape arrays. This leads to a subtle difference in what approaches are open to you.
If you want to use dynamic association with the targets of the component pointers, then you can point the pointer to the target after the target is itself allocated. Something like:
allocate(a(n))
ptrs(1)%p => a
Alternatively, you could consider just using allocatable components:
type ptr
double precision, allocatable :: p(:)
end type ptr
Upvotes: 2
Reputation: 60123
I suggest to always nullify your pointers. That way you won't hit the undefined behaviour cased by undefined pointers so easily.
With the derived type you can use default initialization
type ptr
double precision, pointer :: p(:) => null()
end type ptr
double precision, pointer :: a(:), b(:), c(:)
The pointer a
points to some undefined garbage address.
ptrs(1)%p => a
Now ptrs(1)%p
points to the same garbage address.
allocate(ptrs(i)%p(n))
Now a new target is allocated and ptrs(1)%p
points there. a
is unaffected.
Instead, you now have to point a
to that new address as well.
a => ptrs(1)%p
It is important not to consider a
and ptrs(1)%p
to be two aliases to the same thing. They are not. Both are pointers and both point somewhere. It is your responsibility to make sure they point always to the same address.
Upvotes: 3