数组索引超出范围

L.J*_*L.J 2 arrays fortran

我很困惑如果引用数组元素的索引实际超出其假定范围,Fortran如何处理这种情况.

这是一个简单的代码来说明问题:

PROGRAM test_matrix_out

USE mod_writearray

IMPLICIT NONE
INTEGER :: i,j,m,n
REAL    :: k
REAL, Dimension(:,:),ALLOCATABLE :: A

m = 3
n = 4
ALLOCATE(A(m,n))

k = 1

DO i=1,m
    DO j=1,n
        A(i,j)=k
        k=k+1
    ENDDO
ENDDO

CALL writearray(A)
WRITE(*,*)
WRITE(*,*) A(1,:)
WRITE(*,*)
WRITE(*,*) A(2,:)
WRITE(*,*)
WRITE(*,*) A(0,:)
WRITE(*,*)
WRITE(*,*) A(4,:)
WRITE(*,*)
WRITE(*,*) A(5,:)
WRITE(*,*)
WRITE(*,*) A(100,:)
WRITE(*,*)
WRITE(*,*) A(:,1)
WRITE(*,*)
WRITE(*,*) A(:,2)
WRITE(*,*)
WRITE(*,*) A(:,0)
WRITE(*,*)
WRITE(*,*) A(:,4)
WRITE(*,*)
WRITE(*,*) A(:,5)
WRITE(*,*)
WRITE(*,*) A(:,100)


DEALLOCATE(A)

END PROGRAM test_matrix_out
Run Code Online (Sandbox Code Playgroud)

它给了我以下结果:

   1.000000       2.000000       3.000000       4.000000

   5.000000       6.000000       7.000000       8.000000

  0.0000000E+00   9.000000       10.00000       11.00000

   2.000000       3.000000       4.000000      0.0000000E+00

   6.000000       7.000000       8.000000      0.0000000E+00

  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00

   1.000000       5.000000       9.000000

   2.000000       6.000000       10.00000

 -1.0097448E-28  8.9776148E-39  0.0000000E+00

   4.000000       8.000000       12.00000

  0.0000000E+00  0.0000000E+00  0.0000000E+00

 -3.3631163E-44  1.4293244E-43  0.0000000E+00
Run Code Online (Sandbox Code Playgroud)

为什么会这样?

M. *_* B. 6

当您编写A(i,j)时,编译器会计算该内存位置的地址.例如,参见http://en.wikipedia.org/wiki/Array_data_structure#Multidimensional_arrays.编译器通常不会根据语言规则确定这是否是合法地址.使用超过维度的索引是非法的.程序员有责任不这样做.Fortran的一个优点是能够为此错误添加运行时检查.传统的知识是运行时下标检查是昂贵的,但是当我测试时,我经常发现运行时成本可以忽略不计,有时会在程序的生产版本中保留它.

如果您正在读取内存,则索引错误的可能后果将是获取错误的值,除非内存位置太远以至于它位于属于程序的内存之外,这将产生错误.如果要写入内存,则会损坏阵列中其他位置的内存,属于某个其他变量,或者属于程序的内部数据结构.看看什么样的问题可以解除重新分配的原因?有关索引错误导致程序运行时出现问题的示例问题.


mil*_*cic 5

你看到的是你用来编译程序的编译器没有检查数组是否在运行时超出范围.所以,根据编译器和机器,任何事情都会发生.有时,可以引用未在内存中显式分配的数组元素,这是您的示例中发生的情况.在这种情况下,超出范围的元素的值是在程序运行时位于该存储器地址的任何值.如果请求的内存地址不存在或无法访问,程序将因分段错误而失败.

我只是查看当前Fortran标准的草案,我找不到任何关于访问数组元素是否已定义的行为的声明.为了避免这些问题,请使用-C(check bounds)标志编译程序.如果可能,程序将告诉您哪个数组的哪个元素超出范围.-C在开发期间使用,但不在生产中使用,因为它极大地减慢了代码的速度.

另外,为了将来参考,当提出这种问题时(例如我的程序为什么输出这个?),最好包括有关正在使用的编译器(带有版本号)和目标体系结构的信息.

  • 标准不允许访问数组元素超出范围,但不需要检查ftp://ftp.nag.co.uk/sc22wg5/N1901-N1950/N1915.pdf(也适用于拉格朗日) (2认同)