Non-one indexed array from associate

106 Views Asked by At

I would like to have an associate that points to an array (or parts thereof) and is not one indexed. The following program illustrates the problem:

program test_associate
    implicit none(type, external)
    integer, parameter :: N = 10
    integer :: i, A(0 : N - 1)

    A = [(i, i = lbound(A, 1), ubound(A, 1))]
    write(*, *) A(0), A(9)

    associate(B => A(0 : N - 1))
        write(*, *) B(9)    ! This writes 8 but should write 9
    end associate
end program

I tried

    associate(B(0 : N - 1) => A(0 : N - 1))
        write(*, *) B(9)
    end associate

but this is invalid syntax. (at least in my compiler which is gfortran 9.3)

2

There are 2 best solutions below

3
francescalus On BEST ANSWER

The syntax

associate (B(0:N-1) => ...)
end associate

is not valid in Fortran: the left-hand side of the association item must be a name. With just a name (which here would be B) it isn't possible to specify properties such as bounds.

The bounds of the associating entity array (again, here B), are given by the results of using LBOUND on the right-hand side (the selector) (Fortran 2018, 11.1.3.3 p.1):

The lower bound of each dimension is the result of the intrinsic function LBOUND (16.9.109) applied to the corresponding dimension of selector

The referenced description of LBOUND explains how the bound is calculated in this case.

Because A(0:N-1) is not a whole array, LBOUND returns 1, and so the lower bound of B in this case is itself 1.

It is possible to have the lower bound of B be something other than 1: have the selector being a whole array. In

associate(B => A)
end associate

B will have lower bound that of A.

In conclusion: it's possible for an associate entity to have lower bound other than 1, but only when the thing it's associated with is a whole array. In particular, in associating with part of an array (and that can include all of the array, such as B => A(:), A(:) not being a whole array) the associating entity always has lower bounds 1.

As Vladimir F says in another answer, a pointer can have bounds controlled as part of pointer assignment.

4
Vladimir F Героям слава On

I do not think that is possible. A(0 : N - 1) is a subarray, it is an expression, no longer the original array. The lower bound of A(0 : N - 1) is 1, not 0.

You can try

dimension A(0:9)
print *,lbound(A(0:8))
end

It will print 1.

Be aware, that your associate may case the array section to be copied and stored in a temporary array.

If you associate to => B, A will correctly write 9.

You can use pointers to point to such sections

program test_associate
    implicit none(type, external)
    integer, parameter :: N = 10
    integer, target :: A(0 : N - 1)
    integer, pointer :: B(:)
    integer :: i

    A = [(i, i = lbound(A, 1), ubound(A, 1))]
    write(*, *) A(0), A(9)
    
    B(0:N-1) => A(0:N-1)
    write(*, *) B(9)    ! This writes 9

end program