I am adding a module to a Fortran code, and ran across the following issue. I have a derived data type Info that contains several other variables, among them a 4D pointer array (it is a hydro code, so it is 3 spatial components and 1 variable component). To make my subroutine easier to read, I just make a pointer q and point to Info%q, as follows:
real,pointer::q(:,:,:,:)
q=>Info%q
...
some work on q
The question I am running into is: should I use deallocate(q) before nullify(q)? Or, since q is pointing to an array that is necessary elsewhere in the code, should I just use nullify?
Thanks for your help.
Only nullify! Otherwise the original pointer would be undefined and the array would no longer exist!
Related
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.
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.
I have a pointer uvw(:,:) which is two-dimensional, and I got a 1d buffer array x(:).
Now I need to point uvw(1,:)=>x(1:ncell) and uvw(2,:)=>x(ncell+1:ncell*2) etc.
I made a very simple example. I know that array of pointers does not work, but does anybody have an idea how this can be worked around?
PS: For a pragmatic reason I do not want to wrap my uvw with a declared type. ( i am changing some bit of code, and need uvw as 2D pointer. Currently is an array, and my idea is to avoid changing the way uvw is being used as it being used thousands of times)
program test
real, allocatable,target :: x(:)
real, pointer :: ptr(:,:)
allocate(x(100) )
x = 1.
ptr(1,:) => x(1:10)
end program
The error message says:
`error #8524: The syntax of this data pointer assignment is incorrect:
either 'bound spec' or 'bound remapping' is expected in this context.
[1]
ptr(1,:) => x(1:10)
----^`
You are trying to perform pointer bounds remapping, but you have the incorrect syntax and approach.
Pointer bounds remapping is a way to have the shape of the pointer different from that of the target. In particular, the rank of the pointer and target may differ. However, in such an assignment it is necessary to explicitly specify the lower and upper bounds of the remapping; it isn't sufficient to use : by itself.
Also, you'll need to assign the whole pointer in one go. That is, you can't have "the first ten elements point to this slice, the next ten to this slice" and so on in multiple statements.
The assignment statement would be
ptr(1:10,1:10) => x
Note, that this also means that you can't actually have what you want. You are asking for the elements ptr(1,1:10) to correspond to x(1:10) and ptr(2,2:10) to correspond to x(11:20). That isn't possible: the array elements must match in order: ptr(1:10,1) being the first ten elements of ptr must instead be associated with the first ten elements x(1:10). The corrected pointer assignment above has this.
If you prefer avoiding a pointer, then the UNION/MAP is an option depending on compiler. It was added to gfortran a while ago... then you can think of the array as a rank=2 but also use the vector (Rank=1) for SIMD operations.
All this assumes that one wants to avoid pointers...
That's my first question post ever ... don't be cruel, please.
My problem is the following. I'd like to assign a fortran pointer as an expression. I think that's not possible by simple fortran techniques. But since new fortran versions seem to provide ways to handle things used in C and C++ (like c_ptr and c_f_pointer ... ), maybe someone knows a way to solve my problem. (I have not really in idea about C, but I read that pointer arithmetic is possible in C)
To make things more clear, here is the code which came to my mind immediately but isn't working:
program pointer
real(8),target :: a
real(8),pointer :: b
b=>a*2.0d0 ! b=>a is of course working
do i=1,10
a=dble(i)*2.0d0
write(*,*)b
end do
end program
I know that there are ways around this issue, but in the actual program, all of which came to my mind, would lead to much longer computation time and/or quite wiered code.
Thanks, a lot, in advance!
Best, Peter
From Michael Metcalf,
Pointers are variables with the POINTER attribute; they are not a distinct data type (and so no 'pointer arithmetic' is possible).
They are conceptually a descriptor listing the attributes of the objects (targets) that the pointer may point to, and the address, if any, of a target. They have no associated storage until it is allocated or otherwise associated (by pointer assignment, see below):
So your idea of b=>a*2 doesn't work because b is being assigned to a and not given the value of a.
Expression, in general (there two and a half very significant exceptions), are not valid pointer targets. Evaluation of an expression (in general) yields a value, not an object.
(The exceptions relate to the case where the overall expression results in a reference to a function with a data pointer result - in that case the expression can be used on the right hand side of a pointer assignment statement, or as the actual argument in a procedure reference that correspond to a pointer dummy argument or [perhaps - and F2008 only] in any context where a variable might be required, such as the left hand side of an ordinary assignment statement. But your expressions do not result in such a function reference and I don't think the use cases are relevant to what you wnt to do. )
I think you want the value of b to change as the "underlying" value of a changes, as per the form of the initial expression. Beyond the valid pointer target issue, this requires behaviour contrary to one of the basic principles of the language (most languages really) - evaluation of an expression uses the value of its primaries at the time the expression is evaluation - subsequent changes in those primaries do not result in a change in the historically evaluated value.
Instead, consider writing a function that calculates b based on a.
program pointer
IMPLICIT NONE
real(8) :: a
do i=1,10
a=dble(i)*2.0d0
write(*,*) b(a)
end do
contains
function b(x)
real(kind(a)), intent(in) :: x
real(kind(a)) :: b
b = 2.0d0 * x
end function b
end program
Update: I'm getting closer to what I wanted to have (for those who are interested):
module test
real,target :: a
real, pointer :: c
abstract interface
function func()
real :: func
end function func
end interface
procedure (func), pointer :: f => null ()
contains
function f1()
real,target :: f1
c=>a
f1 = 2.0*c
return
end function f1
end module
program test_func_ptrs
use test
implicit none
integer::i
f=>f1
do i=1,10
a=real(i)*2.0
write(*,*)f()
end do
end program test_func_ptrs
I would be completely satisfied if I could find a way to avoid the dummy arguments (at least in when I'm calling f).
Additional information: The point is that I want to define different functions f1 and deside before starting the loop, what f is going to be inside of the loop (depending on whatever input).
Pointer arithmetic, in the sense of calculating address offsets from a pointer, is not allowed in Fortran. Pointer arithmetic can easily cause memory errors and the authors of Fortran considered it unnecessary. (One could do it via the back door of interoperability with C.)
Pointers in Fortran are useful for passing procedures as arguments, setting up data structures such as linked lists (e.g., How can I implement a linked list in fortran 2003-2008), etc.
I am trying to understand a Fortran code written by someone else. The code is doing what it is supposed to do so I am assuming that it works fine. A subroutine called "fft" is being called from another subroutine called "convol". Inside "convol", an array is declared like this:
real, dimension fri(n+1,n,nh,2,0:1)
call fft(fri)
Inside "fft", the declaration is like this:
subroutine wrft3b(fri)
real, dimension fri(2,n+1,n,nh,0:1)
I don't understand why the array lengths are not consistent and still the code is working. Any clues what might be happening here?
The important thing is that the length is the same. If the interface is not explicit, this will not throw an error for the contiguous explicit-shape array. Only the elements of the array will have different indexes (determined by the column-major order), that in the calling program.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Function pointer arrays in Fortran
How to alias a function name in Fortran
In FORTRAN, how I can create and use a pointer, which points to a subroutine?
Furthermore, is it possible to have a hole array of pointers pointing in various subroutines?
I know that these things can be easily implemented in C, but what about FORTRAN?
EDIT
I have tried to use the command:
PROCEDURE (), POINTER :: pMYSUB => NULL()
I made pMYSUB pointer to point at the subroutine:
pMYSUB => MYSUB
I have also put MYSUB subroutine into INTERFACE:
INTERFACE
SUBROUTINE MYSUB
END SUBROUTINE
END INTERFACE
MYSUB subroutine has no arguments. The problem is that when I use:
call pMYSUB
I get the linking error: unresolved external symbol _pMYSUB.
What I am doing wrong?
The command:
POINTER(pMYSUB, MYSUB)
is another way of making the point pMYSUB to point at the subroutine MYSUB?
Function pointers in Fortran are called "procedure pointers", part of the Fortran 2003 standard. Many modern compilers support them nowadays. There's also a very limited form of function pointer going back to at least F77, where you can have a procedure argument which is a procedure; you cannot have normal function pointer variables before F2003 though. If you have problems even after googling up something based on the above, post some code of yours that you're writing and I'm sure someone will help you out.
Wrt. an array of pointers, that is for some reason not allowed. The common work-around is to create a derived type with a pointer component, then make an array of these derived types.
The problem was that my subroutine's name was DO_CALC, and for some reason the statement:
PROCEDURE (DO_CALC), POINTER :: pDO_CALC => NULL()
didn't like to the compiler. I changed my subroutine's name and now works OK!
#Janneb, nice idea to use an array of derived types instead of an array of function pointers which is isn't allowed in Fortran.