我们之前使用了单个标量变量,在编程实践中,我们往往需要存储并操作一系列数字,这类数字序列通常被统称为数组
。数组是一种多维变量,能够容纳多个值,并且我们可以通过一个或多个索引来访问这些值。在Fortran编程语言中,数组默认是基于1进行索引的
;也就是说,在任何维度上,首个元素的索引均为1。
定义数组
静态声明
在Fortran中,我们能够声明任何类型的数组。声明数组变量时,通常采用两种常见的表示法:一种是使用维度属性(dimension)
,另一种则是在变量名后添加括号内的数组维度。
比如:
integer :: myArray
dimension myArray(5) ! 声明一个包含5个整数元素的一维数组
integer :: myArray(5) ! 同样是声明一个包含5个整数元素的一维数组
接下来举个栗子:
program test
implicit none
! 1维整数数组
integer, dimension(10) :: array1
integer :: array2(10) ! 与array1等效表达的方式
! 2维浮点数组
real, dimension(10, 2) :: array3
! 1维浮点数组
real :: array4(0:9)
real :: array5(-5:5)
! 给数组赋值
array1 = (/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /)
array2 = (/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /)
array3 = reshape((/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &
11, 12, 13, 14, 15, 16, 17, 18, 19, 20 /), (/ 10, 2 /))
print *, array1
print *, array2
print *, array3
print *, array4
print *, array5
end program test
- 这里:
array1 和 array2 被初始化为1到10的整数序列。
array3 使用reshape函数将一个1维数组转换为2维数组。reshape
的第一个参数是要转换的1维数组,第二个参数是新数组的形状(在这里是10x2)。
array4 和 array5 在此示例中未初始化,因此它们将包含默认值(通常是0或某种未定义的值,具体取决于编译器和运行时环境)。
我们如果想要为array4、array5赋值并打印后两位小数,我们可以:
program test
implicit none
! 1维整数数组
integer, dimension(10) :: array1
integer :: array2(10) ! 等效表达方式
! 2维浮点数组
real, dimension(10, 2) :: array3
! 1维浮点数组
real :: array4(0:9)
real :: array5(-5:5)
integer :: i
! 初始化数组
array1 = (/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /)
array2 = (/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /)
array3 = reshape((/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &
11, 12, 13, 14, 15, 16, 17, 18, 19, 20 /), (/ 10, 2 /))
array4 = (/ (i+0.1, i=0,9) /)
array5 = (/ (i-5.0, i=0,10) /)
! 打印数组
print *, 'array1: '
print *, array1
print *, 'array2: '
print *, array2
print *, 'array3: '
do i = 1, size(array3, 1)
print *, array3(i, :)
end do
print *, 'array4: '
do i = lbound(array4, 1), ubound(array4, 1)
print "(F8.2)", array4(i)
end do
print *, 'array5: '
do i = lbound(array5, 1), ubound(array5, 1)
print "(F8.2)", array5(i)
end do
end program test
动态声明
Fortran语言的一个强大特性是它内置了对数组操作的支持;我们可以使用数组切片表示法对数组的全部或部分进行操作。
我们可以使用allocatable
属性来声明动态数组。这意味着数组的大小在编译时是不确定的,而是在程序运行时根据需要分配。使用allocate
语句为动态数组分配内存,当动态数组不再需要时,我们应该使用deallocate
语句来释放它们占用的内存,可以避免内存泄漏。
program allocatable
implicit none
integer, allocatable :: array1(:)
integer, allocatable :: array2(:,:)
integer :: i
allocate(array1(10))
allocate(array2(10,10))
array1 = 0
array2 = 0
do i = 1, 10
array1(i) = i
end do
do i = 1, 10
array2(i,i) = i
end do
print *, "Array1: "
do i = 1, 10
print *, array1(i)
end do
print *, "Array2: "
do i = 1, 10
print *, array2(i,i)
end do
deallocate(array1)
deallocate(array2)
end program allocatable
运行结果如下:
数组切片
Fortran 语言的一个强大特性是它对数组操作的内置支持。我们可以使用数组 切片 表示法对数组的全部或部分执行操作:
program array_slice
implicit none
integer :: i
integer :: array1(10) ! 1D integer array of 10 elements
integer :: array2(10, 2) ! 2D integer array of 100 elements
array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ! Array constructor
array1 = [(i, i = 1, 10)] ! Implied do loop constructor
array1(:) = 0 ! Set all elements to zero
array1(1:5) = 1 ! Set first five elements to one
array1(6:) = 1 ! Set all elements after five to one
array2 = reshape((/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &
11, 12, 13, 14, 15, 16, 17, 18, 19, 20 /), (/ 10, 2 /))
print *, array1(1:10:2) ! Print out elements at odd indices
print *, array2(:,1) ! Print out the first column in a 2D array
print *, array1(10:1:-1) ! Print an array in reverse
end program array_slice
这里我们可以看一看使用python的方法,与Fortran的代码存在一定差别:
import numpy as np
array1 = np.zeros(10, dtype=int)
array1 = np.array([i for i in range(1, 11)])
array1[:] = 0
array1[0:5] = 1
array1[5:] = 1
array2 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20]).reshape(2, 10)
print(array1[0:10:2])
print(array2[0, :])
print(array1[9::-1])
字符串操作
静态字符串
在Fortran中,静态字符串的长度在声明时是固定的。使用character(len=n)
来声明一个长度为n的字符串变量。可以直接将字符串字面量赋值给静态字符串变量,只要字面量的长度不超过变量声明的长度。使用//
运算符可以拼接两个字符串。拼接时,需要确保结果字符串的长度不会超过目标变量的长度。
program string
implicit none
character(len=6) :: first_name
character(len=4) :: last_name
character(11) :: full_name
first_name = 'GGBond'
last_name = 'Dick'
! 拼接字符串
full_name = first_name//' '//last_name
print *, full_name
end program string
可分配字符串
在Fortran里可以使用character(:), allocatable
来声明一个可分配字符串。此时,字符串的长度在声明时是不确定的,需要在后续通过allocate
语句或赋值时动态确定。而使用allocate(character(n) :: variable)
可以显式分配字符串的长度
program allocatable_string
implicit none
character(:), allocatable :: first_name
character(:), allocatable :: last_name
! Explicit allocation statement
allocate(character(4) :: first_name)
first_name = 'Dick'
! Allocation on assignment
last_name = 'Big'
print *, first_name//' '//last_name
end program allocatable_string
字符串数组
字符串数组可以在 Fortran 中表示为character
变量数组。 character
数组中的所有元素都具有相等的长度。但是,可以将不同长度的字符串作为输入提供给数组构造函数,如下例所示。如果它们分别比“字符”数组的声明长度长或短,它们将被截断或用空格右填充。最后,在将值打印到标准输出时,我们使用内部函数trim
删除任何多余的空格。
program string_array
implicit none
character(len=10), dimension(2) :: keys, vals
keys = [character(len=10) :: "user", "dbname"]
vals = [character(len=10) :: "GGBond", "motivation"]
call show(keys, vals)
contains
subroutine show(akeys, avals)
character(len=*), intent(in) :: akeys(:), avals(:)
integer :: i
do i = 1, size(akeys)
print *, trim(akeys(i)), ": ", trim(avals(i))
end do
end subroutine show
end program string_array