Arrays Fortran中数组索引的分段错误
设Arrays Fortran中数组索引的分段错误,arrays,indexing,fortran,Arrays,Indexing,Fortran,设A和I为维数为N的整数类型数组。通常,I是整数1:N的排列。我想做A(1:N)=A(I(1:N))。对于较小的N这很好,但是当N较大时,我得到了分段错误。 下面是我实际做过的一个例子: integer N integer,dimension(:),allocatable::A,I N = 10000000 allocate(A(N)) allocate(I(N)) A = (/ (i,i=1,N) /) I = (/ (N-i+1,i=1,N) /) A(1:N) = A(I(1:N)) 有
A
和I
为维数为N的整数类型数组。通常,I
是整数1:N
的排列。我想做A(1:N)=A(I(1:N))
。对于较小的N
这很好,但是当N
较大时,我得到了分段错误。
下面是我实际做过的一个例子:
integer N
integer,dimension(:),allocatable::A,I
N = 10000000
allocate(A(N))
allocate(I(N))
A = (/ (i,i=1,N) /)
I = (/ (N-i+1,i=1,N) /)
A(1:N) = A(I(1:N))
有更好的方法吗?似乎a(I(1:N))
是有效的语法,至少在我的测试中(gfortran 4.8
,ifort 16.0
,pgfortran 15.10
)。一个问题是i
和i
是同一件事,数组i
不能像您所做的那样用于隐含do。将其替换为j
将生成一个为我运行的程序:
program main
implicit none
integer :: N, j
integer, allocatable, dimension(:) :: A, I
! -- Setup
N = 10000000
allocate(A(N),I(N))
A = (/ (j,j=1,N) /)
I = (/ (N-j+1,j=1,N) /)
! -- Main operation
A(1:N) = A(I(1:N))
write(*,*) 'A(1): ', A(1)
write(*,*) 'A(N): ', A(N)
end program main
至于为什么会出现分段错误,我想当数组大小变大时,内存就会耗尽。但是,如果你仍然有问题,我建议如下
不要使用A(1:N)=A(I(1:N))
,而应该使用循环,例如
! -- Main operation
do j=1,N
Anew(j) = A(I(j))
enddo
A = Anew
这更具可读性,更易于调试。在您的示例中,i是一个数组,您是否将其用作循环变量?这可能吗?值得一提的是,在隐含do循环中使用专用的ii
变量,即使N
=100M(gfortran v.5.4),代码也能正常执行。为了明确这一点,Fortran不区分大小写,因此I
和I
引用相同的变量。My gfortran在(1)处给出错误:循环变量不能是子组件
且无法编译。您的上一个循环不正确,因为您将在r.h.s上访问a
的更改值。我认为您需要先制作一个副本以使用这样的循环。这样更好。我猜A(1:N)=A(I(1:N))
无论如何都会导致编译器在幕后进行复制..在我使用ifort-16的linux设备上,上面的程序会以N>~4*10^6进行分段,因为它的堆栈大小约为10 MB。我猜ifort正在为整个数组分配生成一个临时数组,这可能会导致segfault。gfortran不会出现这种情况,但对于-fstack阵列
,它再次给出segfault(使用堆栈大小为8.5 MB的mac mini)。(因为OP说“代码适用于小N”,可能i
和i
只是打字错误…?)对吧。特别地分配一个副本(这将为新的重新进行)将使过程更加透明,并在默认情况下将其放在堆上。对不起,I
和I
是打字错误。。。复制一份解决问题的方法。这可能是内存问题。我没有尝试使用gfortran,但我在不同的计算机上使用了ifort,更大的内存允许更大的N。谢谢大家。