Search code examples
arrayspointersfortran

Assignment operator in the context of arrays in fortran


If I have two arrays, say A and B, and let's say my declarations are:

real(kind=8) :: A(1, 10)
real(kind=8), intent(in) :: B(1, 20)

where B is an array that I am receiving from somewhere. I have a function F, which needs the data I have stored in B, but B has stored data in packs of 10 (that is, elements 1 to 10 belong to a particular set, 11 to 20 to a different set and so on), so I am using A to store 10 values of B sequentially.

If I call a function by passing A, I am technically passing the address of the first element of the array A right? So if I run a loop:

do i = 1, 2
   A(1, 1) = B(1, 10*i - 9)
   call F(A)
end do

am I actually asking the function F to read from the element (10*i - 9) in the ith loop? (like 1st element in the first loop, 11th element in the second loop) Of course, this is equivalent to writing

do i = 1, 2
   call F(B(1, 10*i - 9))
end do

but I wanted to make it absolutely sure that I understand about passing of array pointers via functions and subroutines properly. Please do let me know if there are some blatant errors in whatever I have said here. Thanks


Solution

  • When the dummy argument of F is declared like

    real(kind=8), intent(in) :: B(1, 10)
    

    we open ourselves up to something called sequence association.1

    In this case the subroutine reference

    call F(B(1, 10*i - 9))
    

    does work on that given element of B and the following nine elements. In that sense, you are "passing the address of the element". Strictly, though, you are passing a sequence of ten elements to the subroutine, not an address. (The compiler will likely implement this as a pass-by-reference, but there is a difference.2)

    In the subroutine reference

    call F(A)
    

    you are referencing the whole array A. There is still a ten element sequence, this time built from the first element of A. Again, this is almost like passing the address of that first element.

    Where you are going wrong, however, is in thinking that

    A(1, 1) = B(1, 10*i - 9)
    

    is working towards what you want. It isn't.

    This assignment is copying one element from B to the first element of A. That's really a copy. It's a brand new value at a brand new address. There's no implied copy of any other element of B to any other element of A.

    You could use a pointer array A with pointer assignment to a section of B, but that's different and in this case quite unnecessary (so I won't by default show). Or a full array section copy of B to the whole array A, but again that's different.

    Finally, don't forget F(B(1,10*i-9:10*i)).


    1 See other questions and answers here; also applies to assumed-size arrays like real B(1,*).

    2 You'll see this difference if you have a compiler happy to check that lengths of the element sequences match. As a naive passing of an address, you can supply a shorter sequence than required and then run over that in the subroutine; as a true sequence, a compiler can warn you that it's too short.