4

I have a question related to one asked some years ago on Intel Developer Forum about the in-place reshaping of an array.

In short, the answer was that an array of a certain rank can be allocated, and a pointer created that refers to the same memory location (i.e. in-place), but with a different rank, e.g.:

use, intrinsic :: ISO_C_BINDING
integer, allocatable, target :: rank1_array(:)
integer, pointer :: rank3_array(:,:,:)
integer :: i

! Allocate rank1_array 
allocate(rank1_array(24))

! Created rank3_pointer to rank1_array
call C_F_POINTER (C_LOC(rank1_array), rank3_array, [3,2,4])

! Now rank3_array is the same data as rank1_array, but a 3-dimension array with bounds (3,2,4)

My question is now that if I deallocate the original array rank1_array, why is it that the pointer rank3_array is still associated, and can be used without a problem (seemingly). Thus, if I append the code segment from above with:

! initialise the allocated array
rank1_array = [(i, i=1,24)]

! then deallocate it
deallocate(rank1_array)

! now do stuff with the pointer
print *, associated(rank3_array)
rank3_array(2,2,1) = 99
print *, rank3_array

Compiling and running this program gives me the output

gfortran -Wall my_reshape.f90 -o my_reshape
./my_reshape
T
1 2 3 4 99 6 7 ... 23 24

If the memory of rank1_array was deallocated, why does rank3_array still function unless it is a copy of the original? Was the initial reshape then in-place or not? Would be very grateful if someone could explain this behaviour to me.

I'm using gfortran 6.1.0 of that is of interest.

Edit/Update:

As the accepted answer by @francescalus indicates, the real issue here is how I (incorrectly!) handled pointers in general and not the in-place reshape with C_F_POINTER in particular. The strange behaviour I saw was just a result of undefined behaviour due to non-compliant fortran code I wrote. Based on @francescalus answer and comments, I did more reading online and thought it might be useful to give a link to a relevant section of a Fortran Reference Manual that very clearly explains how pointers and allocatable arrays should be handled.

jbdv
  • 1,263
  • 1
  • 11
  • 18
  • Although not an answer to the question (and the same issues will exist): pointer bounds remapping is another way to have a pointer of rank different from its target. There are questions to read about that, and it's a term for searching. – francescalus Jun 09 '17 at 00:11
  • @francescalus, I really appreciate your guidance – jbdv Jun 09 '17 at 00:17

1 Answers1

5

That c_f_pointer is used instead of "normal" pointer assignment is not relevant to the problem, nor is the changing shape.

After the call to c_f_pointer the pointer rank3_array is pointer associated with the target rank1_array. There is no copy made.

When rank1_array is deallocated in the statement

 deallocate(rank1_array)

this has an effect on the pointer which has rank1_array as a target. In particular, the pointer association status of rank3_array becomes undefined. (Whenever a pointer's target is deallocated except through the pointer, the pointer's association status becomes undefined.)

With the pointer of undefined association status the next part

print *, associated(rank3_array)

is not allowed. At this point the program is not a Fortran-compliant program (and the compiler needn't detect that) and the processor is allowed to print .TRUE. here if it wants to.

Equally, with

rank3_array(2,2,1) = 99
print *, rank3_array

rank3_array itself is undefined and those references are also not allowed. Again, any effect is available to the compiler.

Now, as in another answer on a similar topic: just because rank1_array has been deallocated that doesn't mean that the memory gets purged. Probably all that happens is some array descriptor for the first array has its status changed. It isn't the compiler's responsibility to do the same to all related pointers/descriptors. (And so the pointer's descriptor may indeed still say "associated".)

It's important to note, though: it may look like it's working, but I wouldn't advise betting your job on it.

francescalus
  • 30,576
  • 16
  • 61
  • 96
  • thanks for the explanation @francescalus. The important thing for me to understand is that if `rank1_array` is deallocated, then the pointer array associated with it (`rank3_array`) will be released as well, right? So after my deallocation statement I should not (and don't have to) do anything more to the pointer `rank3_array`? – jbdv Jun 08 '17 at 23:46
  • 1
    You can't do anything with the "dangling" pointer except point it to something else or nullify it. There are perhaps two points: you can't even ask about its state; it's your responsibility to make sure you don't reference/ask. But equally, there's no leak and you can safely nullify/re-point the pointer. – francescalus Jun 08 '17 at 23:57