Smart questions
Smart answers
Smart people
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Member Login

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips now!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

Join Tek-Tips
*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

LINK TO THIS FORUM!

Add Stickiness To Your Site By Linking To This Professionally Managed Technical Forum.
Just copy and paste the
code below into your site.

Partner With Us!

"Best Of Breed" Forums Add Stickiness To Your Site
Partner Button
(Download This Button Today!)

Feedback

"...These forums are an excellent source and example of the way people can help each other..."

Geography

Where in the world do Tek-Tips members come from?

recursive subroutines and allocatable arraysHelpful Member!(3) 

billgray1234 (Programmer)
28 Jun 12 21:14
i'm using fortran 90/95.
i'm using recursive subroutines.
i need to use arrays within these subroutines. i'm trying to determine whether i can use allocatable arrays, or whether i instead have to use "fixed size" arrays.

as you probably know, when using allocatable arrays, if they have already been allocated (i.e. they are currently in use), then they have to be deallocated first, if they are to be allocated again (i.e. used again).
does this also hold true if :-

1) the allocatable array is used in a recursive subroutine, and
2) the allocatable array is not a part of the subroutine dummy arguement list, and

AFTER the array has been allocated, but BEFORE the array has been deallocated, either :-

3) the recursive subroutine calls itself, or
4) control is "returned" to the calling program (using the word RETURN) ?

for example, is the code below valid, or does the array A have to instead be declared as a "fixed size" array (i.e. have a fixed dimension) ? my guess is that A has to instead be declared as a "fixed size" array.


RECURSIVE SUBROUTINE F ( X1 , X2 )

INTEGER, INTENT (INOUT) :: X1
INTEGER, INTENT (INOUT) :: X2


INTEGER :: IA
REAL, ALLOCATABLE, DIMENSION (:) :: A


IA = 3, say
ALLOCATE ( A (IA) )


IF ( X1 < 5 ) THEN
...X1 = X1 + 1
...CALL F ( X1 , X2 )
ELSE
...perform some "final" calculation with X2, and A
...RETURN
END IF


DEALLOCATE ( A )

END SUBROUTINE F
Helpful Member!  salgerman (Programmer)
28 Jun 12 23:08
I don't have practice with recursion, but I don't see anything wrong with your code.

Your point 4, though is not true...return does not return to the "calling" program, it simply returns to the previous level subroutine F that called this level one....there is another return that you do not show, it is right before "END SUBROUTINE F" ...this is the one that will return this call to the previous level, too, after you are done with the IF-THEN clause and so you will have a chance to de-allocate the array allocated at that level.

Anyway, that's what I see.
Helpful Member!  gummibaer (Programmer)
29 Jun 12 4:32
Question is, if an recursive procedure gets a new set of local variables allocated or not. From the examples in my textbook I would assume that this is the case. So each allocation of a in the recursive procedure would allocate new memory for a new variable a. Then your code seems okay.

But you can pretty fast run out of memory depending on the size of your matrix and the number of recursions. So you should include some errorhandling to have a graceful exit if this occurs:

CODE

allocate (a (ia), status = iError)
if (iError .ne. 0) then
    write (*,*) 'running out of memory'
    return     ! include iError into argument list of F to have a flag that the calling routine could act on.
endif 

In addition you should make sure that you do not produce a memory leak, that is, that all instances of a get deallocated. As far as I understand your code a does not get deallocated if your program returns in the else-if clause. And this seems to be the main exit for the routine, that is all instances return from there when executed successfully. So you may end with a piece of memory unusable equal to the size of a multiplied by the number of recursions. So you should deallocate prior to any return.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

billgray1234 (Programmer)
2 Jul 12 2:02
thanks for your replies.

in reply to your replies :-

Salgerman :- you are correct (as usual!), about the term "calling program". i wrote "calling program", but i meant "calling CODE" -- which refers to the code that called the subroutine. Correct me if i'm wrong, but "calling CODE" refers to either a subroutine / function / main program, depending on which one did the "calling".

gummibaer :- you are also correct (as usual!), about the "incorrect" deallocation of A (due to the IF--ELSE IF--END IF clause) in the code i supplied. instead, the code i supplied SHOULD have looked like this :-


RECURSIVE SUBROUTINE F ( X1 , X2 )

INTEGER, INTENT (INOUT) :: X1
INTEGER, INTENT (INOUT) :: X2


INTEGER :: IA
REAL, ALLOCATABLE, DIMENSION (:) :: A


IA = 3, say
ALLOCATE ( A (IA) )


IF ( X1 < 5 ) THEN
...X1 = X1 + 1
...CALL F ( X1 , X2 )
ELSE
...perform some "final" calculation with X2, and A
...DEALLOCATE ( A )
...RETURN
END IF


DEALLOCATE ( A )


END SUBROUTINE F



finally, to both Salgerman and gummibaer :- i think you are both correct, about the above code being "ok" (i.e. "valid"). each time the recursive subroutine calls itself, we are effectively looking at a fresh "instance" of that subroutine. in each "instance", a new vector A is allocated, but the vector is "local" to that subroutine (i.e. as opposed to being a "global" variable, that can be globally accessed by any subroutine / function / main program). so, based on all of the theory i've read on this topic, i'm thinking the above code IS "ok".
Helpful Member!  FJacq (Programmer)
2 Jul 12 4:16
"calling procedure" instead of "calling code" is the right expression, a procedure being a subroutine, function, main program... which has been compiled.

You do not need to deallocate your allocatable array A. This is done automatically when returning to the calling procedure.

François Jacq

billgray1234 (Programmer)
14 Jul 12 2:07
sorry that this reply is so late.

you said that allocatable arrays (that have been ALLOCATEd in the current "procedure") are automatically deallocated (upon return to the "calling procedure").
does the same apply with files ? i.e. are all files (that have been OPENed during the current "procedure") automatically CLOSEd (upon return to the "calling procedure") ?


also, i just wanted to check something, based on what you said :-

again, you said that allocatable arrays (that have been ALLOCATEd during the current "procedure") are automatically deallocated (upon return to the "calling procedure").
does that mean to say that it's actually NOT good programming practice to "manually" DEALLOCATE arrays, before returning to the "calling procedure" ? because, if i "manually" DEALLOCATE SOME of them (but not ALL of them), then the "procedure" will look incomplete (but will still compile, and run correctly).

ditto with files. if all files (that have been OPENed during the current "procedure") are automatically CLOSEd, then is it NOT good programming practice to "manually" CLOSE all such files ?
gummibaer (Programmer)
14 Jul 12 4:19
Files:

Files stay open as long as your program is running unless you close them by a CLOSE statement or you open another file under the same unit number. When your program terminates, then the system closes and saves the files unless declared otherwise in the OPEN, which is a non-standard option in some compilers (e.g. Compaq allows DISPOSE = 'DELETE' option to be specified in the open statement)

Allocatable arrays:

I think it a matter of personal preference if you rely on the automatic options, that your compiler provides - not only in the deallocation of arrays. I for myself hate all (!) automatic functions. Everywhere. I want to be in control of things, anytime. I even want to have my PC print what I type. If I type garbage, then my PC should print garbage and not autocorrect or autoformat it to something different, thazt I do not recognise. So for me manual deallocation of arrays is good programming practice, as I know for sure at what time the array becomes unavailable. I usually apply the save attribute to my allocatables to stop the system from deallocating of the arrays automatically (which is very important in window callback functions!). This way I get a runtime error (to be checked by the status clause in the allocate statement) when the system tries to allocate an array that allready is allocated. Then I know something in the flow of my prog went wrong, not just the allocation, that a procedure was called when it should not be called. This is essential for me as I do Window-applications where the program flow depends deeply on the user's actions.

That's just me, other may have different views with their good reasons for it.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Back To Forum

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close