Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

How to Allocate structure data in subroutine and return data through pointer ref

smk
Beginner
1,294 Views

Dear Forum,

I'm having trouble figuring out how to properly allocate my defined type in a subroutine and return the data to the main program using a structure pointer passed to the subroutine. I suspect I am making an easy mistake but I can't find the right way to set this up and help would be greatly appreciated.

compiled, version 18.0.1.156 Build 20171018

ifort datTest.f90

On execute I get: "forrtl: severe (157): Program Exception - access violation" as soon as I try to access structure.

Test code, datTest.f90, below.

Thanks!

 

module Test
implicit none
type myArrObj
real , allocatable, dimension(:):: dat
end type myArrObj
contains
subroutine getDataPtr(dPtr)
real, pointer , dimension(:) , intent(out)::dPtr
real , allocatable, target, dimension(:):: mydata
 
allocate(mydata(10))
mydata=7.0
dPtr=>mydata
return
end subroutine getDataPtr
subroutine getDataObject(dPtr)
type(myArrObj), pointer, intent(out)::dPtr
type(myArrObj), target:: mydata
 
allocate(mydata%dat(10))
mydata%dat=5.0
dPtr=>mydata
print *, dPtr%dat ! Allocation happend and data is here
return
end subroutine getDataObject
end module Test
 
program datTest
use Test
type(myArrObj), pointer ::ObjPtr=>null()
real, pointer, dimension(:) :: ArrayPtr=>null()
 
call getDataPtr(ArrayPtr)
print *, ArrayPtr ! Allocation done in subroutine and data returns w pointer
 
call getDataObject(ObjPtr)
print *, ObjPtr%dat ! forrtl: severe (157): Program Exception - access violation
end program datTest
0 Kudos
1 Solution
FortranFan
Honored Contributor II
1,294 Views

@keller, scott,

Note the two allocated objects in your two subroutines, getDataPtr and getDataObject, are "local" to those procedures and when the execution returns from those subprograms, those objects can get destroyed.  If you intended for your "mydata" objects to be "global: objects instead with "saved" status, you may consider explicit instructions for the same by placing them in your MODULE itself i.e., before the CONTAINS section:

module Test

   implicit none

   type myArrObj
      real , allocatable, dimension(:) :: dat
   end type myArrObj

   ! Declare "global" objects that are saved
   real, allocatable, target, save :: mydata1(:)
   type(myArrObj), target, save :: mydata2

contains

   subroutine getDataPtr(dPtr)

      real, pointer , dimension(:) , intent(out)::dPtr

      allocate(mydata1(10))

      mydata1 = 7.0

      dPtr => mydata1

      return

   end subroutine getDataPtr

   subroutine getDataObject(dPtr)

      type(myArrObj), pointer, intent(out)::dPtr

      allocate(mydata2%dat(10))

      mydata2%dat = 5.0

      dPtr => mydata2

      print *, dPtr%dat ! Allocation happend and data is here

      return

   end subroutine getDataObject

end module Test


program datTest

   use Test

   type(myArrObj), pointer :: ObjPtr => null()

   real, pointer, dimension(:) :: ArrayPtr => null()

   call getDataPtr(ArrayPtr)
   print *, ArrayPtr ! Allocation done in subroutine and data returns w pointer

   call getDataObject(ObjPtr)
   print *, ObjPtr%dat ! forrtl: severe (157): Program Exception - access violation

end program datTest

Separately, you may want to consider moving away from POINTER attribute and work with ALLOCATABLE attribute in Fortran and move away from "globally" saved objects and rather have data in objects allocated in the calling code and given your use of OO-like getter procedures, perhaps you may want to look into OO features in Fortran and employ them instead.  The references in this Dr Fortran blog can be helpful for details: https://software.intel.com/en-us/blogs/2013/12/30/doctor-fortran-in-its-a-modern-fortran-world

View solution in original post

0 Kudos
2 Replies
FortranFan
Honored Contributor II
1,295 Views

@keller, scott,

Note the two allocated objects in your two subroutines, getDataPtr and getDataObject, are "local" to those procedures and when the execution returns from those subprograms, those objects can get destroyed.  If you intended for your "mydata" objects to be "global: objects instead with "saved" status, you may consider explicit instructions for the same by placing them in your MODULE itself i.e., before the CONTAINS section:

module Test

   implicit none

   type myArrObj
      real , allocatable, dimension(:) :: dat
   end type myArrObj

   ! Declare "global" objects that are saved
   real, allocatable, target, save :: mydata1(:)
   type(myArrObj), target, save :: mydata2

contains

   subroutine getDataPtr(dPtr)

      real, pointer , dimension(:) , intent(out)::dPtr

      allocate(mydata1(10))

      mydata1 = 7.0

      dPtr => mydata1

      return

   end subroutine getDataPtr

   subroutine getDataObject(dPtr)

      type(myArrObj), pointer, intent(out)::dPtr

      allocate(mydata2%dat(10))

      mydata2%dat = 5.0

      dPtr => mydata2

      print *, dPtr%dat ! Allocation happend and data is here

      return

   end subroutine getDataObject

end module Test


program datTest

   use Test

   type(myArrObj), pointer :: ObjPtr => null()

   real, pointer, dimension(:) :: ArrayPtr => null()

   call getDataPtr(ArrayPtr)
   print *, ArrayPtr ! Allocation done in subroutine and data returns w pointer

   call getDataObject(ObjPtr)
   print *, ObjPtr%dat ! forrtl: severe (157): Program Exception - access violation

end program datTest

Separately, you may want to consider moving away from POINTER attribute and work with ALLOCATABLE attribute in Fortran and move away from "globally" saved objects and rather have data in objects allocated in the calling code and given your use of OO-like getter procedures, perhaps you may want to look into OO features in Fortran and employ them instead.  The references in this Dr Fortran blog can be helpful for details: https://software.intel.com/en-us/blogs/2013/12/30/doctor-fortran-in-its-a-modern-fortran-world

0 Kudos
smk
Beginner
1,294 Views

@FortranFan: Thanks so much for your post, it helped me understand the deallocate behavior in the subroutine better and your comments pointed me in the direction I was looking for. It was even easier to do what I was hoping.  I'm attaching the modified version in case anyone else is interested in the same issue.

module Test
implicit none
type myArrObj
real , allocatable, dimension(:):: dat
end type myArrObj
contains
function getDataObject()
type(myArrObj) :: getDataObject
allocate(getDataObject%dat(10))
getDataObject%dat=5.0
return
end function getDataObject
end module Test
program datTest
use Test
type(myArrObj) ,target:: Obj
Obj= getDataObject()
print *, Obj%dat
end program datTest
0 Kudos
Reply