From: Ragu on 1 Apr 2010 11:48 Pointer nullify and deallocate I have to use an array of pointers for my program. I am thinking that an array of pointers will be more efficient to code and easier to maintain than handling three multi-dimensional arrays for x, y and z directions. I started my first test program after browsing the text books (MRC and Chapman). In S.J.Chapman. 3rd edition, Chapter 15, Page 756 it is said thus: When dynamic memory is deallocated in a DEALLOCATE statement, the pointer to the memory is automatically nullified. However, if there are other pointers pointing to that same memory, they must be manually nullified or reassigned. If not, In MRC F95/2003, Page 106, Section 6.5.4 it is said that Because often there are other ways to access a target (for example, through another pointer), the NULLIFY statement does not deallocate the targets. If deallocation is also required, a DEALLOCATE statement should be executed instead. I havent checked F2003 handbook yet. While I was playing with my test program, I found out that MRC is correct and that SJC is not so (or I am misinterpreting SJC or not understanding SJC correctly). In the test program, I get a YES for associated status after a deallocate. So my question is: 1) Am I interpreting SJC correctly? 2) Should a deallocate be executed first before nullify or it does not matter? I am thinking that it should not matter as long as they are done one after another. 3) As I am planning to use this sample technique for multi-dimensional arrays, are there any best-practices / pitfalls that I should be aware of? Thanks. program firstpointer implicit none integer, parameter :: dp_k = selected_real_kind(p=15, r=300) real(kind=dp_k), dimension(:), allocatable, target :: x, y, z integer :: ii type dim1arrptr real(kind=dp_k), dimension(:), pointer :: p => null() end type dim1arrptr type (dim1arrptr), dimension(3) :: val continue ! Fill array with data allocate(x(3), y(2), z(4)) x = (/(real(ii,kind = dp_k), ii = 2,4) /) y = (/(real(ii,kind = dp_k), ii = 3,4) /) z = (/(real(ii,kind = dp_k), ii = 4,7) /) ! print values write(*, '(A)') 'Initial Values' write(*, '(A,4F5.2)') 'array x : ', x write(*, '(A,4F5.2)') 'array y : ', y write(*, '(A,4F5.2)') 'array z : ', z ! associate arrays with pointer val(1)%p => x val(2)%p => y val(3)%p => z ! print values write(*, '(/A)') 'Pointer Values' write(*, '(A,4F5.2)') 'val(1) : ', (val(1)%p(ii), ii = 1, 3) write(*, '(A,4F5.2)') 'val(2) : ', (val(2)%p(ii), ii = 1, 2) write(*, '(A,4F5.2)') 'val(3) : ', (val(3)%p(ii), ii = 1, 4) write(*,'(A,L1)') 'val(1)%p associated ? ', associated(val(1)%p) write(*,'(A,L1)') 'val(2)%p associated ? ', associated(val(2)%p) write(*,'(A,L1)') 'val(3)%p associated ? ', associated(val(3)%p) ! deallocate write(*, '(/A)') 'Deallocate X, Y, Z arrays' deallocate(x, y, z, STAT = ii) if(ii /= 0) then write(*,'(A)') 'Dealloc was not successful' else write(*,'(A)') 'Dealloc was successful' endif write(*,'(A,L1)') 'val(1)%p associated ? ', associated(val(1)%p) write(*,'(A,L1)') 'val(2)%p associated ? ', associated(val(2)%p) write(*,'(A,L1)') 'val(3)%p associated ? ', associated(val(3)%p) ! nullify write(*, '(/A)') 'Nullify Pointers' if(associated(val(1)%p)) nullify(val(1)%p) if(associated(val(2)%p)) nullify(val(2)%p) if(associated(val(3)%p)) nullify(val(3)%p) write(*,'(A,L1)') 'val(1)%p associated ? ', associated(val(1)%p) write(*,'(A,L1)') 'val(2)%p associated ? ', associated(val(2)%p) write(*,'(A,L1)') 'val(3)%p associated ? ', associated(val(3)%p) end program firstpointer
From: Ragu on 1 Apr 2010 11:51 Here's the output: Initial Values array x : 2.00 3.00 4.00 array y : 3.00 4.00 array z : 4.00 5.00 6.00 7.00 Pointer Values val(1) : 2.00 3.00 4.00 val(2) : 3.00 4.00 val(3) : 4.00 5.00 6.00 7.00 val(1)%p associated ? T val(2)%p associated ? T val(3)%p associated ? T Deallocate X, Y, Z arrays Dealloc was successful val(1)%p associated ? T val(2)%p associated ? T val(3)%p associated ? T Nullify Pointers val(1)%p associated ? F val(2)%p associated ? F val(3)%p associated ? F
From: Richard Maine on 1 Apr 2010 12:20 Ragu <ssragunath(a)gmail.com> wrote: > Pointer nullify and deallocate > > I have to use an array of pointers for my program. I am thinking that > an array of pointers will be more efficient to code and easier to > maintain than handling three multi-dimensional arrays for x, y and z > directions. I started my first test program after browsing the text > books (MRC and Chapman). In S.J.Chapman. 3rd edition, Chapter 15, Page > 756 it is said thus: > "When dynamic memory is deallocated in a DEALLOCATE statement, the > pointer to the memory is automatically nullified. However, if there > are other pointers pointing to that same memory, they must be manually > nullified or reassigned. If not, …" > > In MRC F95/2003, Page 106, Section 6.5.4 it is said that > "Because often there are other ways to access a target (for example, > through another pointer), the NULLIFY statement does not deallocate > the targets. If deallocation is also required, a DEALLOCATE statement > should be executed instead." > > I haven't checked F2003 handbook yet. > > While I was playing with my test program, I found out that MRC is > correct and that SJC is not so (or I am misinterpreting SJC or not > understanding SJC correctly). In the test program, I get a YES for > associated status after a deallocate. > > So my question is: > 1) Am I interpreting SJC correctly? No, you are not. Both books are correct and say the same thing. Your quote from MRC starts out talking about the deallocate statement, while the one from SJC starts out talking about the nullify statement, but both get around to saying the same things (and both do so correctly). A deallocate statement deallocates and nullifies. A nullify statement just nullifies, but does not deallocate. > 2) Should a deallocate be executed first before nullify or it does not > matter? I am thinking that it should not matter as long as they are > done one after another. Phrased the way you just did, it matters a lot. If you want to deallocate the space, you must use a deallocate statement. There is no other way (for pointers). Nullify will not do it. Nor will anything else. Doing a nullify after the deallocate is pointless, but also mostly harmless. Probably the main element of harm is in the confusion. Oh. hold on.... I now that I look at your code, I see what is going on. It wasn't evident to me from the words. You have both allocatables and pointers here. That makes a difference. All the above comments are true (including those in both books), but they are solely about pointers. Allocatables are different (and can never be nullified - the concept does not apply). Your code requires both the deallocate and the nullify (at least to be clean). That's because you have 2 separate things - the allocatable and a pointer to it. You need the deallocate to deallocate the allocatable. But that will only deallocate the allocatable. It won't do anything to the pointer that points to it. That pointer will be left trying to point to space that is no longer allocated. It is good practice to nullify the pointer to get it out of that state. Note that even asking about the association status of the pointer is illegal right after the deallocate. Any results you might get from such are likely to be inconsistent garbage (and might even crash the program). That's part of why you want to nullify it. But.... I wouldn't do it this way in the first place.... > 3) As I am planning to use this sample technique for multi-dimensional > arrays, are there any best-practices / pitfalls that I should be aware > of? Looks to me like you are just looking for allocatable components with no need for pointers to be involved. If that's the case, I recommend you do it that way. Pointers have *MANY* pitfalls. They can be used as substitutes for allocatables, but they are much more confusing in that role and you are far more likely to get things wrong. Allocatables should just work. You have added the extra complication of having both an allocatable and a separate pointer to it. As far as I can see, you don't need the two things. If you just have the allocatable components, with no pointers, things should be much simpler. Allocatable components do require either f2003 or the allocatable TR to f95, but most compilers support at least the TR by now. -- Richard Maine | Good judgment comes from experience; email: last name at domain . net | experience comes from bad judgment. domain: summertriangle | -- Mark Twain
From: Ragu on 1 Apr 2010 13:10 Richard, Thanks. I believe that I need the pointers to allocatable arrays. Let me explain my situation: I have an array currently declared as real(kind = dp_k), dimension(:,:,:), allocatable :: tfs ! tfs or Transfer Functions ! Rank 1 --> nfreq or number of frequencies ! Rank 2 --> 3*3 Directions ! Rank 3 --> nnodes or number of nodes In the current setup, I loop across the nine directions while printing to output files. The code is clean. The values are printed to output as Do ii = 1, 9 write(funit,'(100F16.4)') maxval(tfs(1:nfreq,ii,jj),dim = 1),jj = 1, nnodes) End do ! ii, 1 to 9 The above assumes that the nnodes and nfreq are same for the 9 directions. The newer situation demands that a situation where nfreq are same for the first 3, next 3 and last 3 of Rank=2. So I am trying to split it as real(kind = dp_k), dimension(:,:,:), allocatable :: xtfs, ytfs, ztfs ! Rank 1 --> nfreq(idir) or Total number of frequencies ! Rank 2 --> 3 Directions (not 3*3) ! Rank 3 --> nnodes When I am adding an extra dimension to the problem, then I allocate memory as Select case(idir) Case(1) allocate(xtf(nfreq(idir),3,nnodes)) Case(2) allocate(ytf(nfreq(idir),3,nnodes)) Case(3) allocate(ztf(nfreq(idir),3,nnodes)) End select Then I have to link them to array of pointers. type dim3arrptr real(kind=dp_k), dimension(:,:,:), pointer :: p => null() end type dim3arrptr type (dim3arrptr), dimension(3) :: tfs ! assign pointers as tfs(1)%p => x tfs(1)%p => y tfs(1)%p => z When I am printing the results, I can do Do ii = 1, 3 Do jj = 1, 3 write(funit,'(100F16.4)') maxval(tfs(ii)%p(1:nfreq(ii),jj,kk),dim = 1),kk = 1, nnodes) End do ! jj, 1 to 3 minor dirs End do ! ii, 1 to 3 arrays This will maintain the old code structure and avoid splitting the existing code into a repetitive mode for printing arrays xtfs, ytfs and ztfs. I haven't written the actual code and compiled. So this is kind of a pseudo code. Do you think this is the right path? Thanks. Ragu
From: Richard Maine on 1 Apr 2010 14:58
Ragu <ssragunath(a)gmail.com> wrote: > Thanks. I believe that I need the pointers to allocatable arrays. Let > me explain my situation: I don't see how this translates into needing pointers to allocatable arrays. You showed how you are accessing the data through the pointers, but that doesn't illustrate the need for them to be pointers as far as I can see. You only need pointers when something is going to be accessed via 2 or more different ways. You only showed one way, so I can do that without pointers. > When I am adding an extra dimension to the problem, then I allocate > memory as > Select case(idir) > Case(1) > allocate(xtf(nfreq(idir),3,nnodes)) > Case(2) > allocate(ytf(nfreq(idir),3,nnodes)) > Case(3) > allocate(ztf(nfreq(idir),3,nnodes)) > End select > > Then I have to link them to array of pointers. > type dim3arrptr > real(kind=dp_k), dimension(:,:,:), pointer :: p => null() > end type dim3arrptr > > type (dim3arrptr), dimension(3) :: tfs > > ! assign pointers as > tfs(1)%p => x > tfs(1)%p => y > tfs(1)%p => z I assume this is supposed to be index values 1, 2, and 3. Anyway... Instead of making an array of pointers (with the usual derived-type trick), you could just make an array of allocatables using the same trick, as in type dim3allocptr real(kind=dp_k), allocatable, dimension(:,:,:) :: p end type type(dim3allocptr), dimension(3) :: tfs Then just directly allocate tfs(1)%p(nfreq(idir),3,nnodes), and likewise for tfs(2)%p and tfs(3)%p. Now if you want to have that structure and *ALSO* keep some other structure such as the separate xtf, ytf, and ztf, then you would have an argument for pointers. Perhaps you do. But this wasn't clear to me. My main point is that you don't need pointers for any one way of accessing the data. You only need pointers if you are accessing it via two different routes. That's pretty much one of the most fundamental differences between pointers and allocatables. There are some other cases, but that's a biggie. -- Richard Maine | Good judgment comes from experience; email: last name at domain . net | experience comes from bad judgment. domain: summertriangle | -- Mark Twain |