2012-07-19 113 views
2

我很困惑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 

它给了我以下结果:

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 

为什么会出现这种情况?

回答

6

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

如果你正在读内存索引错误的可能后果将获得一个错误的值,除非存储位置是如此的遥远,它是属于程序,这将创建一个故障记忆之外。如果您正在写入内存,则会损坏阵列中其他位置的内存,属于某个其他变量,或者属于程序的内部数据结构。有关索引错误导致程序运行时出现问题的示例问题,请参见what kind of problems can lack of deallocation cause?

5

您所看到的是您用来编译程序的编译器不检查数组是否在运行时出界。所以,取决于编译器和机器,什么都可以。有时,可能会引用内存中未明确分配的数组元素,这就是您的示例中所发生的情况。在这种情况下,超出边界的元素的值就是程序运行时在该内存地址处的任何值。如果请求的存储器地址不存在或无法访问,则程序将因分段故障而失败。

我只是在寻找在目前Fortran标准的草案,我找不到任何关于是否访问数组元素越界是一个定义的行为的任何声明。为了避免这些问题,请使用-C(检查边界)标志编译您的程序。如果可能的话,程序会让你知道哪个数组的哪个元素超出了界限。在开发过程中使用-C,但在生产中不使用,因为它极大地降低了代码的速度。另外,为了将来的参考,在提出这类问题时(例如为什么我的程序输出这个问题?),最好包括正在使用的编译器(带有版本号)和目标体系结构的信息。

+2

标准不允许访问数组元素超出范围,但不需要检查ftp://ftp.nag.co.uk/sc22wg5/N1901-N1950/N1915.pdf(拉格朗日的读数也很好) – 2012-07-19 07:53:17

+0

非常感谢你们!非常有用的评论! – 2012-07-19 12:14:53

+0

@VladimirF谢谢!很高兴知道。 – milancurcic 2012-07-19 14:28:28