2

I need to get rid of some libraries that a Fortran program uses, so I have to create all the subroutines in the Library used in the program.

One of those subroutines is memory allocation which is done by C language.

I created my own subroutine for the allocation

MODULE ARRAY_ALLOCATION
  CONTAINS
     SUBROUTINE ARRAY_ALLOCATE (ARR, ARR_SIZE, ARR_IDX, CODE_RET)
            ! DECLARE AN ALLOCATABLE PARAMETER
            INTEGER, ALLOCATABLE, INTENT (INOUT) :: ARR(:)
            INTEGER, INTENT (IN) :: ARR_SIZE,ARR_IDX,CODE_RET
            INTEGER :: IDX_END
            IDX_END = ARR_IDX + ARR_SIZE -1
            ALLOCATE (ARR(ARR_IDX:IDX_END))
            RETURN
     END SUBROUTINE ARRAY_ALLOCATE

     SUBROUTINE ARRAY_DEALLOCATE (ARR)
            INTEGER, ALLOCATABLE, INTENT (INOUT) :: ARR(:)
            DEALLOCATE (ARR)
            RETURN
       END SUBROUTINE ARRAY_DEALLOCATE

END MODULE 

but I need to keep the declaration of the array which done like this integer alist(1) without the attribute allocatable.

example

    program test1

USE ARRAY_ALLOCATION
implicit none

integer alist(1)

call ARRAY_ALLOCATE(alist,5,3,1)
CALL Test(ALIST)
CALL ARRAY_DEALLOCATE(alist)

error

error #7976: An allocatable dummy argument may only be argument associated with an allocatable actual argument

Is there a way I can make my array allocatable after the declaration ? I'm thinking of making it allocatable (after declaration) Inside the subroutine allocating memory so that in don't have to change the declaration in my old program.

tsumey
  • 63
  • 1
  • 11
  • 2
    What _exactly_ is the error message? Something about [explicit interfaces](http://stackoverflow.com/q/16881363)? – francescalus Aug 19 '16 at 08:44
  • hi, yes it's about explicit interface _Error: Dummy argument of procedure has an attribute that requieres an explicit interface for this procedure_ – tsumey Aug 19 '16 at 08:54
  • 1
    @tsumey, please, put your code in the question. The routine declaration and how you are calling it should be sufficient. – Jauch Aug 19 '16 at 08:59
  • @Jauch hi jauch, i edited the message, it works now i don't know how..., i need to keep the declaration used before, without mentionning that the array is allocatable, is it possible to make an array allocatable withing a subroutine ? – tsumey Aug 19 '16 at 09:24
  • @tsumey, prefer the (:) form instead of the (*) form. See here: http://stackoverflow.com/questions/24543329/assumed-size-arrays-colon-vs-asterisk-dimension-arr-vs-arr – Jauch Aug 19 '16 at 09:31
  • @tsumey, You meant an allocatable array that exists only inside a subroutine and is not passed to outside it? Yes, it is possible. The memory will be freed when going out of the scope (if nothing else to prevent this exists). – Jauch Aug 19 '16 at 09:35
  • 1
    BTW did you know theat you don't have to use RETURN at the and of each subroutine and STOP at the and of each program? They are completely unnecessary. – Vladimir F Героям слава Aug 19 '16 at 09:37
  • 1
    *"the compiler says something about interfaces..."* Please **don't** do this. If the compiler says something important, you **must** copy the message here exactly. – Vladimir F Героям слава Aug 19 '16 at 09:39
  • Also please take more care about how you are writing. Use capital letters at the start of each sentence. Use capital I. Don't put stop space before "?". Don't repeat tags in the title. – Vladimir F Героям слава Aug 19 '16 at 09:44
  • I strongly suppose that it is a duplicate of http://stackoverflow.com/questions/9374691/array-and-pointer-shapes Your opinion? Also related http://stackoverflow.com/questions/9439197/calling-a-subroutine-in-fortran-segmentation-fault?noredirect=1&lq=1 – Vladimir F Героям слава Aug 19 '16 at 09:46
  • @VladimirF sorry for the mess hope it is clear now – tsumey Aug 19 '16 at 11:53
  • @Holmz i don't have the script of the libraries and they are compiled in UNIX. – tsumey Aug 19 '16 at 11:54
  • Why aren't you using `type(c_ptr) and real(C_DOUBLE)` from the intrinsic module `ISO_C_binding`? This will improve your code's interoperability between Fortran and C. – jlokimlin Aug 19 '16 at 16:10

2 Answers2

1

is there a way i can make my array allocatable after the declaration ? i'm thinking of making it allocatable (after declaration) Inside the subroutine allocating memory so that in don't have to change the declaration in my old program.

No.

The error message is very explicit. You can't pass a non allocatable array as argument to a function that is expecting an allocatable array.

The following declaration:

integer alist(1)

Is creating an array of 1 dimension of size 1.

If you want your arrays to be allocated dynamic, you must change them to allocatable or use pointers.

EDIT

As from here: http://web.stanford.edu/class/me200c/tutorial_77/12_arrays2.html

Most programmers prefer to use the asterisk notation to emphasize that the "real array length" is unknown. Some old Fortran 77 programs may declare variable length arrays like this:

  real x(1), y(1)

This is legal syntax even if the array lengths are greater than one! But this is poor programming style and is strongly discouraged.

P.S. This notation is used INSIDE subroutines to define variable length array arguments.

EDIT 2

The following code, based on yours, demonstrate the use of allocatable.

MODULE ARRAY_ALLOCATION
CONTAINS
 SUBROUTINE ARRAY_ALLOCATE (ARR, ARR_SIZE, ARR_IDX, CODE_RET)
        ! DECLARE AN ALLOCATABLE PARAMETER
        INTEGER, ALLOCATABLE, INTENT (INOUT) :: ARR(:)
        INTEGER, INTENT (IN) :: ARR_SIZE,ARR_IDX,CODE_RET
        INTEGER :: IDX_END
        IDX_END = ARR_IDX + ARR_SIZE -1
        ALLOCATE (ARR(ARR_IDX:IDX_END))
        ARR = 1
        RETURN
 END SUBROUTINE ARRAY_ALLOCATE

 SUBROUTINE ARRAY_DEALLOCATE (ARR)
        INTEGER, ALLOCATABLE, INTENT (INOUT) :: ARR(:)
        DEALLOCATE (ARR)
        RETURN
   END SUBROUTINE ARRAY_DEALLOCATE

subroutine Create (arr)
    INTEGER, ALLOCATABLE, INTENT (INOUT) :: ARR(:)
    call ARRAY_ALLOCATE(arr,5,3,1)
end subroutine Create

subroutine Destroy (arr)
    INTEGER, ALLOCATABLE, INTENT (INOUT) :: ARR(:)
    CALL ARRAY_DEALLOCATE(arr)
end subroutine Destroy 

END MODULE 

program Console1

USE ARRAY_ALLOCATION
implicit none

integer, allocatable :: alist(:)
if (allocated(alist)) then
    print *, "is allocated"
else
    print *, "is not allocated"
endif
call Create(alist)
if (allocated(alist)) then
    print *, "is allocated"
else
    print *, "is not allocated"
endif    
print *, alist
CALL Destroy(alist)
if (allocated(alist)) then
    print *, "is allocated"
else
    print *, "is not allocated"
endif
end program Console1

The expected result would be something like this:

is not allocated
is allocated
          1           1           1           1           1
is not allocated

EDIT 3

About allocatable arrays, a simple explanation on why someone would want to deallocate can be found here https://www.phy.ornl.gov/csep/pl/node17.html:

Allocatable arrays are those explicitly declared ALLOCATABLE. An allocatable array may be local to a procedure or may be placed in a module and effectively be global to all procedures of the application. An allocatable array is explicitly allocated with the ALLOCATE statement, and deallocated either explicitly with the DEALLOCATE statement or, if it is a local array for which SAVE has not been specified, automatically upon exit from the procedure. (If SAVE has been specified, local allocatable arrays can persist from one execution of the procedure to the next - they must be explicitly deallocated with a DEALLOCATE statement.) A global allocatable array persists until it is explicitly deallocated, which may occur in a procedure different from the one in which it was allocated.

As can be seen, there are situations where deallocating an allocatable array must be done manually, if necessary.

Jauch
  • 1,500
  • 9
  • 19
  • Ok, so how can I use pointers to allocate ? Side question : I can'y deallocate Inside another subroutine why `error #7976: An allocatable dummy argument may only be argument associated with an allocatable actual argument.` – tsumey Aug 19 '16 at 13:13
  • To use pointers, you must declare your array as a pointer array: int, pointer :: array(:). You than allocate it using allocate the same way you would use for an allocatable array. But in most cases, allocatable has advantages. Using pointers, the system will never freed the memory when the array goes out of scope, and you would have a memory leak if you don't do that manually. – Jauch Aug 19 '16 at 13:15
  • @tsumey, regarding the use of allocatable, see the edit 2 in the answer :) – Jauch Aug 19 '16 at 13:26
  • *"This is legal syntax even if the array lengths are greater than one! But this is poor programming style and is strongly discouraged."* No, As far as I know it is not legal in FORTRAN 77. It was used before assumed size arrays were introduced, but it is not legal to reference any other element than the first one. It just abuses the lack of bounds checking. – Vladimir F Героям слава Aug 19 '16 at 13:29
  • Thank you for your answers, the deallocation doesn't work when I allocate in subroutineA and try to deallocate in subroutineB, do you think that i just don't deallocate them and the deallocation will be done automatically ? – tsumey Aug 19 '16 at 13:58
  • What do you mean by "allocate in subroutineA and deallocate in subroutineB"? The example that I passed to you allocates the array in subroutine ARRAY_ALLOCATEand deallocate it in another subroutine ARRAY_DEALLOCATE. What is different from your example? I tested the example and it works. – Jauch Aug 19 '16 at 14:02
  • @jauch I meant using `ARRAY_ALLOCATE` in a subroutine and `ARRAY_DEALLOCATE` in another subroutine – tsumey Aug 19 '16 at 16:41
  • @tsumey, I update the answer to do that. Now, the allocate is called inside a subroutine and the deallocate inside other. WHile you have your array "above" them all, there is no problem. THe program still compiles without errors and the result is the same. – Jauch Aug 19 '16 at 17:05
  • Explicitly deallocating the array in `ARRAY_DEALLOCATE` is not necessary. Simply change the intent of dummy argument to `integer, allocatable, intent(out) :: arr(:)` and leave the subroutine's body empty. The OP's code demonstrates a basic lack of understanding about how memory is managed dynamically in Fortran. FYI, memory associated with `allocatable` variables is automatically released when they leave scope. No memory leak is possible. This is precisely why the `allocatable` attribute is preferred over the `pointer` attribute 99.9% of the time. – jlokimlin Aug 19 '16 at 17:52
  • @jlokimlin, I think the "adjectivation" of the OP is not necessary (and rude). I updated the answer to show why sometimes it is necessary deallocate an allocatable array (if necessary). – Jauch Aug 19 '16 at 18:24
  • I apologize if my comments aimed at the original poster (OP) were perceived as rude or condescending. It was not at all my intent. I'm here to help and offer my advice. – jlokimlin Aug 19 '16 at 19:50
  • @Jauch Your 3rd edit links to the Fortran 90 standard which is nearly 3 decades old. Starting with Fortran 95, allocatable arrays must be released by the compiler when they leave scope (this was an oversight in the previous Fortran 90 standard). Lastly, Fortran 2008 states that every variable declared in a module before the `contains` statement automatically inherits the `save` attribute. – jlokimlin Aug 19 '16 at 19:57
  • @jlokimlin, It's a pitty that most of the programs in Fortran are still bound to Fortran 95, 90 and even 77. In any case, being old or not, freeing memory from an allocatable is still part of the standard and in some situations is still required, as well as in some situations, (much more than 1%), using a pointer is more useful than an allocatable. – Jauch Aug 19 '16 at 20:09
0

You may not want to get rid of the libraries, but rather make the code work in them.

Generally it is something like: in a library...

MODULE A_Style   !(_*_)
IMPLICIT NONE
PUBLIC: Aye

  CONTAINS
  SUBROUTINE Aye(A)
  REAL, DIMENSION(:), ALLOCATABLE, INTENT(INOUT) :: A
  !...
  IF(ALLOCATED(A)) THEN
    WRITE(*,*)' I see A as A(',LBOUND(A,1),':',UBOUND(A,1),')'
  ELSE
    WRITE(*,*)' I see A as "UNALLOCATED"'
  ENDIF
  !...
  RETURN
  END SUBROUTINE Aye

  SUBROUTINE MakeAye(A, SizeA)
  REAL, DIMENSION(:), ALLOCATABLE, INTENT(INOUT) :: A
  !...
  IF(ALLOCATED(A)A) DEALLOCATE(A)
  ALLOCATE(A(SizeA))
  !...
  RETURN
  END SUBROUTINE MakeAye

END MODULE A_Style

Using the library:

PROGRAM TestA
USE A_Style  !(_*_)
IMPLICIT NONE
REAL, DIMENSION(:), ALLOCATABLE :: A
INTEGER                         :: Size_A = 100
...
CALL Aye(A)
ALLOCATE(A(Size_A))
CALL Aye(A)
...
IF(ALLOCATED(A)) DEALLOCATE(A)
END PROGRAM TestA

Sometimes, and interestingly, the subroutine needs to be in a module for the BOUNDS to be seen. INTENT( OUT) will not see then, so (INOUT) or (IN ) needs to be used.

Holmz
  • 714
  • 7
  • 14
  • Thank you Holmz. there's no way i can use the labraries because they only exist in unix and my program i'm tryng to run it in Windows so i have to create my own one.... do you think there is a way to allocate with fortran decalred like this _DOUBLE PRECISION VREAL(1)_ ? i'm tryng to avoid editing all arrays declaration im my **huge** program – tsumey Aug 19 '16 at 09:51
  • @tsumey You son't have to change those. The `VREAL(1)` can stay almost everywhere. You still didn't show the error message, but I suppose it is about TEST, not about ALLOCATE. **Have you read my comments?** – Vladimir F Героям слава Aug 19 '16 at 10:30
  • @VladimirF ok, look at the error message in the answer bellow. – tsumey Aug 19 '16 at 11:23
  • Why is your code in all caps? Beginning with Fortran 90, lowercase letters are formally permitted, and all known compiler vendors support them. Words spelled with all lowercase letters tend to be more legible than those spelled using only uppercase ones. Furthermore, there is little chance of confusing the letter `i` with the numeral `1,` the letter `B` with the numeral `8,` etc., which can be a problem with some fonts. – jlokimlin Aug 19 '16 at 17:57
  • Since fortran in the 50's the case has not mattered. F90 did not change that. So there are a variety of schemes used. Personally I use upper case for intrinsic Fortran stuff and also for some library calls. Usually CamelCase for variables. If you are working with others then everyone shed b eon the same page. – Holmz Aug 20 '16 at 00:48