# Arrays#

Arrays are a central object in Fortran. The creation of dynamic sized arrays is discussed in the allocatable arrays section.

To pass arrays to procedures four ways are available

*assumed-shape*arrays*assumed-rank*arrays*explicit-shape*arrays*assumed-size*arrays

The preferred way to pass arrays to procedures is as *assumed-shape* arrays

```
subroutine f(r)
real(dp), intent(out) :: r(:)
integer :: n, i
n = size(r)
do i = 1, n
r(i) = 1.0_dp / i**2
end do
end subroutine f
```

Higher-dimensional arrays can be passed in a similar way.

```
subroutine g(A)
real(dp), intent(in) :: A(:, :)
...
end subroutine g
```

The array is simply passed by

```
real(dp) :: r(5)
call f(r)
```

In this case no array copy is done, which has the advantage that the shape and size
information is automatically passed along and checked at compile and optionally at
runtime.
Similarly, array strides can be passed without requiring a copy of the array but as
*assumed-shape* descriptor:

```
real(dp) :: r(10)
call f(r(1:10:2))
call f(r(2:10:2))
```

This should always be your default way of passing arrays in and out of subroutines. Avoid passing arrays as whole slices, as it obfuscates the actual intent of the code:

```
real(dp) :: r(10)
call f(r(:))
```

In case more general arrays should be passed to a procedure the *assumed-rank*
functionality introduced in the Fortran 2018 standard can be used

```
subroutine h(r)
real(dp), intent(in) :: r(..)
select rank(r)
rank(1)
! ...
rank(2)
! ...
end select
end subroutine h
```

The actual rank can be queried at runtime using the `select rank`

construct.
This easily allows to create more generic functions that have to deal with
different array ranks.

*Explicit-shape* arrays can be useful for returning data from functions.
Most of their functionality can be provided by *assumed-shape* and *assumed-rank*
arrays but they find frequent use for interfacing with C or in legacy Fortran
procedures, therefore they will be discussed briefly here.

To use *explicit-shape* arrays, the dimension has to be passed explicitly as dummy
argument like in the example below

```
subroutine f(n, r)
integer, intent(in) :: n
real(dp), intent(out) :: r(n)
integer :: i
do i = 1, n
r(i) = 1.0_dp / i**2
end do
end subroutine
```

For high-dimensional arrays additional indices have to be passed.

```
subroutine g(m, n, A)
integer, intent(in) :: m, n
real(dp), intent(in) :: A(m, n)
...
end subroutine
```

The routines can be invoked by

```
real(dp) :: r(5), s(3, 4)
call f(size(r), r)
call g(size(s, 1), size(s, 2), s)
```

Note that the shape is not checked, so the following would be legal code that will potentially yield incorrect results:

```
real(dp) :: s(3, 4)
call g(size(s), 1, s) ! s(12, 1) in g
call g(size(s, 2), size(s, 1), s) ! s(4, 3) in g
```

In this case the memory layout is preserved but the shape is changed.
Also, *explicit-shape* arrays require contiguous memory and will create temporary
arrays in case non-contiguous array strides are passed.

To return an array from a function with *explicit-shape* use

```
function f(n) result(r)
integer, intent(in) :: n
real(dp) :: r(n)
integer :: i
do i = 1, n
r(i) = 1.0_dp / i**2
end do
end function
```

Finally, there are *assumed-size* arrays, which provide the least compile-time and run-time
checking and can be found frequently in legacy code. They should be avoided
in favour of *assumed-shape* or *assumed-rank* arrays.
An *assumed-size* array dummy argument is identified by an asterisk as the last dimension,
this disables the usage of this array with many intrinsic functions, like `size`

or
`shape`

.

To check for the correct size and shape of an *assumed-shape* array the `size`

and
`shape`

intrinsic functions can be used to query for those properties

```
if (size(r) /= 4) error stop "Incorrect size of 'r'"
if (any(shape(r) /= [2, 2])) error stop "Incorrect shape of 'r'"
```

Note that `size`

returns the total size of all dimensions. To obtain the shape of
a specific dimension add it as second argument to the function.

Arrays can be initialized by using an array constructor

```
integer :: r(5)
r = [1, 2, 3, 4, 5]
```

The array constructor can be annotated with the type of the constructed array

```
real(dp) :: r(5)
r = [real(dp) :: 1, 2, 3, 4, 5]
```

Implicit do loops can be used inside an array constructor as well

```
integer :: i
real(dp) :: r(5)
r = [(real(i**2, dp), i = 1, size(r))]
```

In order for the array to start with different index than 1, do:

```
subroutine print_eigenvalues(kappa_min, lam)
integer, intent(in) :: kappa_min
real(dp), intent(in) :: lam(kappa_min:)
integer :: kappa
do kappa = kappa_min, ubound(lam, 1)
print *, kappa, lam(kappa)
end do
end subroutine print_eigenvalues
```