Using lbound and ubound for Array Bounds in Fortran

In Fortran, arrays are a fundamental data structure that is used for storing and manipulating collections of values. Sometimes, it’s essential to know the bounds (size or limits) of an array, especially when working with dynamic arrays or when passing arrays between subroutines. Fortran provides two built-in functions, lbound and ubound, that allow you to obtain the lower and upper bounds of an array, respectively.

In this post, we will explain the lbound and ubound functions in Fortran, demonstrate how to use them, and explore their significance in practical applications.

What Are lbound and ubound?

  • lbound(array): This function returns the lower bound of the array, i.e., the smallest index that can be used to access elements in the array.
  • ubound(array): This function returns the upper bound of the array, i.e., the largest index that can be used to access elements in the array.

Both functions are useful for determining the valid index range for accessing elements in an array. They are especially helpful when working with arrays that have dynamic sizes or when dealing with arrays that are passed as arguments to subroutines and functions.


Syntax

lower_bound = lbound(array, dimension)
upper_bound = ubound(array, dimension)
  • array: The array for which the bounds are being determined.
  • dimension (optional): The dimension of the array for which you want to find the bounds. If not specified, the function assumes you are asking about the first dimension of the array.

Note that the default lower bound is often 1 for arrays declared with the default indexing, but it can be different if the array has a custom lower bound.


Example 1: Using lbound and ubound with a Static Array

Let’s start with a simple example using a statically declared array, where we explicitly define the lower and upper bounds.

Code Example:

program bounds_example
  integer :: arr(1:10)
  integer :: lower_bound, upper_bound

  lower_bound = lbound(arr)
  upper_bound = ubound(arr)

  print *, "Lower bound: ", lower_bound
  print *, "Upper bound: ", upper_bound
end program bounds_example

Output:

Lower bound: 1
Upper bound: 10

In this example:

  • We declared an array arr with bounds from 1 to 10.
  • The lbound(arr) returns 1, and the ubound(arr) returns 10, indicating the valid indices of the array.

Example 2: Using lbound and ubound with Multi-dimensional Arrays

For multi-dimensional arrays, you can use the lbound and ubound functions to obtain the bounds for each dimension.

Code Example:

program multi_dimensional_bounds
  integer :: arr(1:5, 2:6)
  integer :: lower_bound1, upper_bound1, lower_bound2, upper_bound2

  lower_bound1 = lbound(arr, 1)  ! Lower bound for the first dimension
  upper_bound1 = ubound(arr, 1)  ! Upper bound for the first dimension
  lower_bound2 = lbound(arr, 2)  ! Lower bound for the second dimension
  upper_bound2 = ubound(arr, 2)  ! Upper bound for the second dimension

  print *, "Lower bound of dimension 1: ", lower_bound1
  print *, "Upper bound of dimension 1: ", upper_bound1
  print *, "Lower bound of dimension 2: ", lower_bound2
  print *, "Upper bound of dimension 2: ", upper_bound2
end program multi_dimensional_bounds

Output:

Lower bound of dimension 1: 1
Upper bound of dimension 1: 5
Lower bound of dimension 2: 2
Upper bound of dimension 2: 6

In this case:

  • The first dimension has bounds from 1 to 5, so the lower bound for dimension 1 is 1 and the upper bound is 5.
  • The second dimension has bounds from 2 to 6, so the lower bound for dimension 2 is 2 and the upper bound is 6.

Example 3: Dynamic Arrays with lbound and ubound

When working with dynamic arrays (arrays that are allocated during runtime), you may not know the exact size of the array at compile time. Using lbound and ubound can help you determine the bounds of such arrays at runtime.

Code Example:

program dynamic_bounds
  integer, allocatable :: arr(:)
  integer :: lower_bound, upper_bound
  integer :: n

  print *, "Enter the size of the array: "
  read *, n

  allocate(arr(1:n))  ! Allocating array dynamically

  lower_bound = lbound(arr)
  upper_bound = ubound(arr)

  print *, "Lower bound: ", lower_bound
  print *, "Upper bound: ", upper_bound

  deallocate(arr)  ! Deallocating the array
end program dynamic_bounds

Output:

Enter the size of the array:
10
Lower bound: 1
Upper bound: 10

In this case:

  • The user inputs the size of the array (e.g., 10), and the array is dynamically allocated.
  • The lbound(arr) and ubound(arr) functions return 1 and 10, respectively, because the default lower bound is 1 and the array is allocated with size 10.

Example 4: Using lbound and ubound in Subroutines

You can pass arrays with dynamic bounds to subroutines, and inside the subroutine, use lbound and ubound to access the bounds of the array. This is particularly useful when dealing with multi-dimensional arrays or when the bounds of the array may vary based on input.

Code Example:

program bounds_in_subroutine
  integer :: arr(1:5), lower_bound, upper_bound

  arr = [10, 20, 30, 40, 50]

  call print_bounds(arr)

contains

  subroutine print_bounds(array)
integer, dimension(:) :: array
integer :: lower_bound, upper_bound
lower_bound = lbound(array)
upper_bound = ubound(array)
print *, "Array bounds in subroutine:"
print *, "Lower bound: ", lower_bound
print *, "Upper bound: ", upper_bound
end subroutine print_bounds end program bounds_in_subroutine

Output:

Array bounds in subroutine:
Lower bound: 1
Upper bound: 5

Here:

  • The arr array is passed to the print_bounds subroutine.
  • Inside the subroutine, lbound(array) and ubound(array) return the bounds of the array, which are 1 and 5, respectively.

Practical Use Cases for lbound and ubound

  1. Iterating over arrays dynamically: If you want to iterate over an array but the bounds are not known at compile time (for example, in a dynamically allocated array), you can use lbound and ubound to determine the correct bounds.
  2. Validating array indices: Before accessing an element in an array, you can check if the index is within the bounds using lbound and ubound.
  3. Subroutine/Function flexibility: When writing generic subroutines or functions that work with arrays, lbound and ubound make your code more flexible by allowing it to work with arrays of different sizes or dimensions.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *