数组索引超出范围

时间:2022-11-20 16:41:39

I am confused how Fortran handle the situation if the index for referencing an element of an array is actually out of its supposed range.

如果引用数组元素的索引实际上超出了预期范围,那么Fortran会如何处理这种情况呢?

Here is a simple code to illustrate the problem:

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

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

It gives me the following result:

它给出了如下结果:

   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

Why does this happen?

这为什么会发生?

2 个解决方案

#1


6  

When you write A(i,j) the compiler calculates the address of of that memory location. See, for example, http://en.wikipedia.org/wiki/Array_data_structure#Multidimensional_arrays. The compiler normally doesn't determine whether this is a legal address according to the rules of the language. Using indices past the dimensions is illegal. It is the responsibility of the programmer not to do this. One of the advantages of Fortran is the ability to add run-time checks for this mistake. The conventional lore is that run-time subscript checking is expensive but I when I have tested I have frequently found the runtime cost to be negligible and sometimes leave it on in production versions of programs.

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

If you are reading memory the likely consequence of an index mistake will be to obtain a wrong value, unless the memory location is so far off that it is outside the memory belonging to the program, which will create a fault. If you are writing to memory you will corrupt memory elsewhere in the array, belonging to some other variable, or belonging to an internal data structure of the program. See what kind of problems can lack of deallocation cause? for an example question where an index error caused runtime problems with a program.

如果您正在读取内存,那么一个索引错误的可能结果将是获得一个错误的值,除非内存位置离程序的内存位置太远,从而导致错误。如果您正在写入内存,您将破坏数组中其他地方的内存,这些内存属于其他变量,或者属于程序的内部数据结构。看看什么类型的问题会导致缺乏交易的原因?对于一个示例问题,索引错误导致程序运行时出现问题。

#2


5  

What you are seeing is that the compiler you use to compile the program is not checking whether the arrays get out of bounds at run-time. So, depending on the compiler and machine, anything goes. At times, array elements that are not explicitly allocated in memory are possible to be referenced, which is what happens in your example. In this case, the value of the element that is out of bounds is whatever value is sitting at that memory address at program run-time. If the memory address requested does not exist or cannot be accessed, the program will fail with a segmentation fault.

您所看到的是用来编译程序的编译器不检查数组是否在运行时脱离了边界。所以,根据编译器和机器,任何东西都可以。有时,未显式地分配到内存中的数组元素可以被引用,这就是在示例中发生的情况。在本例中,超出界限的元素的值是程序运行时位于该内存地址的任何值。如果所请求的内存地址不存在或无法访问,程序将会由于段错误而失败。

I was just looking at the draft of the current Fortran standard, and I could not find any statement about whether accessing array elements out of bounds is a defined behaviour. In order to avoid these issues, compile your program with -C (check bounds) flag. If possible, the program will let you know which element of which array went out of bounds. Use -C during development, but not in production, because it slows down the code tremendously.

我只是在查看当前Fortran标准的草案,我找不到任何关于在边界之外访问数组元素是否为已定义行为的语句。为了避免这些问题,使用-C(检查边界)标记编译程序。如果可能的话,程序将告诉您哪个元素的数组超出了界限。在开发过程中使用-C,但在生产过程中不使用-C,因为它极大地降低了代码的速度。

Also, for future reference, when asking questions of this kind (e.g. why my program outputs this?), it is best to include information about the compiler being used (with version number) and target architecture.

另外,为了以后的参考,当您提出此类问题(例如,为什么我的程序输出这个?)时,最好包含有关正在使用的编译器(以及版本号)和目标体系结构的信息。

#1


6  

When you write A(i,j) the compiler calculates the address of of that memory location. See, for example, http://en.wikipedia.org/wiki/Array_data_structure#Multidimensional_arrays. The compiler normally doesn't determine whether this is a legal address according to the rules of the language. Using indices past the dimensions is illegal. It is the responsibility of the programmer not to do this. One of the advantages of Fortran is the ability to add run-time checks for this mistake. The conventional lore is that run-time subscript checking is expensive but I when I have tested I have frequently found the runtime cost to be negligible and sometimes leave it on in production versions of programs.

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

If you are reading memory the likely consequence of an index mistake will be to obtain a wrong value, unless the memory location is so far off that it is outside the memory belonging to the program, which will create a fault. If you are writing to memory you will corrupt memory elsewhere in the array, belonging to some other variable, or belonging to an internal data structure of the program. See what kind of problems can lack of deallocation cause? for an example question where an index error caused runtime problems with a program.

如果您正在读取内存,那么一个索引错误的可能结果将是获得一个错误的值,除非内存位置离程序的内存位置太远,从而导致错误。如果您正在写入内存,您将破坏数组中其他地方的内存,这些内存属于其他变量,或者属于程序的内部数据结构。看看什么类型的问题会导致缺乏交易的原因?对于一个示例问题,索引错误导致程序运行时出现问题。

#2


5  

What you are seeing is that the compiler you use to compile the program is not checking whether the arrays get out of bounds at run-time. So, depending on the compiler and machine, anything goes. At times, array elements that are not explicitly allocated in memory are possible to be referenced, which is what happens in your example. In this case, the value of the element that is out of bounds is whatever value is sitting at that memory address at program run-time. If the memory address requested does not exist or cannot be accessed, the program will fail with a segmentation fault.

您所看到的是用来编译程序的编译器不检查数组是否在运行时脱离了边界。所以,根据编译器和机器,任何东西都可以。有时,未显式地分配到内存中的数组元素可以被引用,这就是在示例中发生的情况。在本例中,超出界限的元素的值是程序运行时位于该内存地址的任何值。如果所请求的内存地址不存在或无法访问,程序将会由于段错误而失败。

I was just looking at the draft of the current Fortran standard, and I could not find any statement about whether accessing array elements out of bounds is a defined behaviour. In order to avoid these issues, compile your program with -C (check bounds) flag. If possible, the program will let you know which element of which array went out of bounds. Use -C during development, but not in production, because it slows down the code tremendously.

我只是在查看当前Fortran标准的草案,我找不到任何关于在边界之外访问数组元素是否为已定义行为的语句。为了避免这些问题,使用-C(检查边界)标记编译程序。如果可能的话,程序将告诉您哪个元素的数组超出了界限。在开发过程中使用-C,但在生产过程中不使用-C,因为它极大地降低了代码的速度。

Also, for future reference, when asking questions of this kind (e.g. why my program outputs this?), it is best to include information about the compiler being used (with version number) and target architecture.

另外,为了以后的参考,当您提出此类问题(例如,为什么我的程序输出这个?)时,最好包含有关正在使用的编译器(以及版本号)和目标体系结构的信息。