早期的Fortran程序多使用静态数组。在编译时,静态数组被分配固定的存储空间,且在程序运行过程中静态数组的大小是不会改变的。为了能够存储足够多的数据,静态数组的大小需要足够大,这会造成内存的浪费。如果静态数组的大小不够大,程序的运行也可能会出现错误。
在Fortran90标准之后,我们可以很方便地使用可分配数组。使用allocatable属性定义可分配数组,allocate和deallocate语句动态地为数组分配和释放内存。使用size语句可以查询可分配数组的大小(元素总数)。
若一个可分配数组的内存已经被释放了,数组内元素的总数是0。然而,笔者最近发现,仍然用size语句查询其大小,得到的结果却是上一次其被分配的大小。 以下面的测试程序为例:
program size_test
implicit none
integer,allocatable :: values(:)
call modify_size(5)
call modify_size(0)
contains
subroutine modify_size(n)
implicit none
integer :: n
integer :: i
if (allocated(values)) deallocate(values)
if (n>0) then
allocate(values(n))
values = 1
end if
write(*,"(A,I0)") "size ofvalues = ",size(values)
do i=1,size(values)
write(*,"(A,I0,A,I0)")"values(",i,") = ",values(i)
end do
end subroutine modify_size
end program size_test
其中,values作为可分配数组。子程序modify_size通过输入参数n来给values分配内存,若n>0则将values的大小设置为n并赋值values为1,否则不给values分配内存。随后输出values的大小和所有元素的值。主程序中先取modify_size的输入参数为5,再取0。编译程序并运行,输出如下所示:
size of values = 5
values(1) = 1
values(2) = 1
values(3) = 1
values(4) = 1
values(5) = 1
size of values = 5
forrtl: severe (174): SIGSEGV, segmentation faultoccurred
Image PC Routine Line Source
size_test 000000000040400D Unknown Unknown Unknown
libpthread-2.17.s 00002B004C5575E0 Unknown Unknown Unknown
size_test 0000000000403150 Unknown Unknown Unknown
size_test 0000000000402C1E Unknown Unknown Unknown
libc-2.17.so 00002B004C785C05 __libc_start_main Unknown Unknown
size_test 0000000000402B29 Unknown Unknown Unknown
第一轮输出完全正确,values的大小被设置成了5,并且数组中的元素全是1。然而第二次调用modify_size时,释放values的内存后没有分配values的大小,size(values)的值还是5。在输出values的值时程序会报错。
这个例子说明当使用可分配数组时,查询可分配数组的大小前需要先查询其是否被分配了内存,即用allocated()查询,否则得到的数组的大小可能是这个数组上一次被分配的大小。