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

How do you determine the upper bound of an allocated array of pointers

John6
Beginner
1,174 Views
I have an allocated array of pointers which I have passed into a subroutine through the argument list.
Inside the subroutine, the array is declared as Type(PointerArray), Dimension(*) :: pArray
What I would like to know is how to determine the upper bound of this array from within the subroutine itself (ubound didn't work, I think because the array is allocated at run-time).

The elements contained in the pArray are pointers to derived types.
What I am trying to do is iterate through the elements of the pArray.
If I iterate using some limit, I would need to test to see whether each pointer in the array is associated.
I know in my testing that the array has 5 elements. I need to exit before the 6th is accessed, and this didn't seem to work: If (.not.(Associated(pArray(i)%pCase))) Exit
Note the pCase is a pointer to a derived type.

If I knew the ubound of the array, I could just iterate using that value.
Anyone have any ideas?
0 Kudos
8 Replies
Steven_L_Intel1
Employee
1,174 Views
If you use Dimension(:), and are passing this from Fortran with an explicit interface visible to the caller, then you can use UBOUND on the array. If it is being passed from C or some other language, then you'll have to pass the bound separately. With Dimension(*) no bound information is passed.

Note that Fortran does not have the concept of "array of pointers". Using an array of derived type with pointer components, as you are in the subroutine, is the Fortran way of doing this.
0 Kudos
John6
Beginner
1,174 Views
If I used Dimesion(:) as you state above, wouldn't that mean that the allocation needs to be done in the same subroutine?
In this case, I have the allocation done in a subroutine two levels up the call stack.
Maybe I'm not quite understanding what you mean by "an explicit interface visible to the caller".

Also, I don't understand why the If (.not.(Associated(pArray(i)%pCase))) Exit didn't work (this is during a Do...Loop). The derived-type pointer pCase was fine for the first 5 elements, and the associated function returned true as expected, but on the sixth element (the array had only 5 elements) I was thinking that the "associated" would return false and I could just exit the iteration. (This was my second option to try to iterate through the pArray... The first was just to use UBOUND).
0 Kudos
Steven_L_Intel1
Employee
1,174 Views
No, Dimension(:) simply means an assumed-shape array. If you use this as a dummy argument, the caller passes the bounds. An explicit interface to the called routine is required to be visible to the caller. For more on that see here. This is what you want.

ASSOCIATED is not going to help you here as you are referencing uninitialized data.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,174 Views
Associated is equivilent to C/C++'s test for pointer not NULL
Your array of 5 pointers, was just that: 5 pointers.
The memory following those 5 pointers is undefined, most likely junk, and most likely not NULL.
It is your responsibility to assure that the number of elements of the array can be known (if this is important for your program).

>>Maybe I'm not quite understanding what you mean by "an explicit interface visible to the caller".

subroutine caller
interface
subroutine callee(A)
real :: A(:)
end subroutine callee
end interface
real :: B(1234)
...
call callee(B)
end subroutine caller
---- may have file break here ---
subroutine callee(C)
real :: C(:)
...
end subroutine callee

When compiling caller, the compiler has an interface declaration for callee, and can observe that callee is requesting arguments that is REAL, and is a rank 1 array, and is requesting that the bounds of the array be passed with the call (or reference back to original array descriptor).

Without the interface, the compiler does not know if to pass an array descriptor or pass the address of the first element of the array.

Apparently your choice ofcoding resulted in the address of the first element of the array to be passed to an unbounded array.

It is generally recommended to place your interfaces into a module and then USE the interface module.

Jim Dempsey
0 Kudos
Steven_L_Intel1
Employee
1,174 Views
Rather than put interface blocks in a module, put the routine you're calling in the module. In general, creating interface blocks for Fortran routines should be discouraged.
0 Kudos
John6
Beginner
1,174 Views
Thanks, I now have it working. I am a still a little confused onone aspect, however.
I was able to get the code working two ways, and I'd like to know which one is considered to be "better".

1. Subroutine caller contains an internal interface block at the top with only a declaration of the arguments:

Subroutinecaller (App)
Interface
Subroutine H_ECHO (App, ActiveCases)
Include 'H.fi'
Type (HApplication) :: App
Type(PointerArray) :: ActiveCases(:)
End Subroutine H_ECHO
End Interface

Type(PointerArray), Dimension(:), Allocatable :: Cases
...
Call H_ECHO (App, Cases)
...
Return
End Subroutine caller

The second method was to encapsulate the entire subroutine H_ECHO (the "callee") in a module, complete with all of the executable code. In this case instead ofputting a specific interfaceblock(see above) into subroutine caller, I put a "Use H_ECHO1" statement into the caller. So in one example an interface block is used, and in another no interface block is used, but instead "Use" and "Contains" statements are used.

The "callee" (for the second method) looks like:

Module H_ECHO1
Contains
Subroutine H_ECHO (App, ActiveCases)
Implicit None
Include 'H.fi'
Type (HApplication), Target :: App
Type(PointerArray), Dimension(:) :: ActiveCases
...
Return
End Subroutine H_ECHO
End Module H_ECHO1

Which one of these techniques is considered "better" (if any) and why?

0 Kudos
Wendy_Doerner__Intel
Valued Contributor I
1,174 Views
Steve's out this week, but I think he would recommend the second way because interfaces can be error prone and use/modules more direct. For reference his comments in this article on the error message emitted for mismatched interfaces.

------

Wendy

Attaching or including files in a post



0 Kudos
Steven_L_Intel1
Employee
1,174 Views
Wendy is right - in general, writing INTERFACE blocks for Fortran routines should be discouraged. I understand that someone updating an old application might choose to do this to help fight errors, but if you have the choice, putting the Fortran code in a module (or making it a contained procedure) is the better solution.
0 Kudos
Reply