Fortran子例程顺序调用异常:最后一个子例程未执行求助
Fortran子例程调用问题:sd子例程未执行的排查思路
我编写了一个调用内部模块多子例程的Fortran程序,子例程按顺序调用。测试发现前两次子例程调用可正常执行,但最后一个sd子例程始终未执行,将其改为函数后问题仍存在。以下是程序代码及输入文件:
程序代码
module tmod contains subroutine readata(fname,tm,hd,td,nrec) ! read input data and returns arrays implicit none integer :: io,i integer,intent(in) :: nrec character(len=40) :: fname real(kind=8),allocatable,intent(out) :: tm(:),hd(:),td(:) allocate(tm(nrec-1)) allocate(hd(nrec-1)) allocate(td(nrec-1)) open(10,file=fname,status='old',action='read') read(10,*) do i=1,nrec-1 read(10,*) tm(i),hd(i),td(i) end do close(10) return end subroutine readata subroutine fd(nrec,t_arr,v_arr,derv_arr) implicit none integer,intent(in) :: nrec integer :: i real(kind=8),allocatable,intent(out) :: derv_arr(:) real(kind=8),dimension(:),intent(in) :: t_arr, v_arr allocate(derv_arr(nrec-2)) do i=2,nrec-1 derv_arr(i)= (v_arr(i+1)-v_arr(i-1))/(t_arr(i+1)-t_arr(i-1)) end do return end subroutine fd subroutine sd(nrec,t_arr,v_arr,derv2_arr) implicit none integer,intent(in) :: nrec integer :: i real(kind=8),dimension(:),intent(in) :: t_arr,v_arr real(kind=8),allocatable,intent(out) :: derv2_arr(:) allocate(derv2_arr(nrec-2)) do i=2,nrec-1 derv2_arr(i)=(v_arr(i+1)-2*v_arr(i)+v_arr(i-1)) end do return end subroutine sd end module tmod program main use tmod implicit none character(len=40) :: filename real(kind=8),allocatable :: tg(:), hg(:), tig(:),pd2(:), sed(:), pd1(:) integer :: nrg ! input parameters filename="test_data.dat" nrg=5 ! calling subroutines call readata(filename, tg, hg, tig, nrg) write(*,*) hg call fd(nrg,tg,tig,sed) write(*,*) "First" write(*,*) sed call fd(nrg,tg,hg,pd1) write(*,*) "First 1" write(*,*) pd1 call sd(nrg,tg,hg,pd2) write(*,*) "Second" write(*,*) pd2 end program maintype
输入文件 test_data.dat
t h ti 0 12.113 1.1e-3 15 12.123 1.12e-3 30 12.156 1.11e-3 45 12.134 1.15e-3
问题排查与解决思路
1. 核心问题:数组越界访问
sd子例程看起来未执行,实际是内存访问错误导致程序崩溃,根本原因是数组索引越界:
- 当
nrg=5时,readata分配的数组hg/tg大小为nrec-1=4(索引1~4)。 sd子例程中,derv2_arr被分配为nrec-2=3(索引1~3),但循环范围是i=2,nrec-1(即i从2到4),此时derv2_arr(4)超出数组边界,触发内存错误,程序直接终止,后续的write(*,*)语句无法执行。- 同样,
fd子例程也存在相同的越界问题,只是未触发致命错误,属于隐性bug。
2. 修正方案
调整数组分配与循环范围
针对差分计算的逻辑,原数组大小为nrec-1时,一阶/二阶中心差分的结果数组大小应为nrec-3(仅能计算中间点的差分),同时调整循环索引:
修正后的fd子例程:
subroutine fd(nrec,t_arr,v_arr,derv_arr) implicit none integer,intent(in) :: nrec integer :: i real(kind=8),allocatable,intent(out) :: derv_arr(:) real(kind=8),dimension(:),intent(in) :: t_arr, v_arr ! 一阶中心差分结果大小为nrec-3 allocate(derv_arr(nrec-3)) ! 循环范围改为2到nrec-2,对应结果数组的索引1到nrec-3 do i=2, nrec-2 derv_arr(i-1) = (v_arr(i+1)-v_arr(i-1))/(t_arr(i+1)-t_arr(i-1)) end do end subroutine fd
修正后的sd子例程:
subroutine sd(nrec,t_arr,v_arr,derv2_arr) implicit none integer,intent(in) :: nrec integer :: i real(kind=8),dimension(:),intent(in) :: t_arr,v_arr real(kind=8),allocatable,intent(out) :: derv2_arr(:) ! 二阶差分结果大小为nrec-3 allocate(derv2_arr(nrec-3)) do i=2, nrec-2 derv2_arr(i-1) = (v_arr(i+1) - 2*v_arr(i) + v_arr(i-1)) end do end subroutine sd
修正主程序笔误
主程序最后一行end program maintype是笔误,应改为:
end program main
3. 辅助排查手段
- 开启编译警告:使用
gfortran -Wall -Wextra编译,编译器会直接提示数组越界的潜在问题。 - 调试模式运行:添加
-g编译选项,用gdb调试程序,可直接定位到内存错误的具体位置。
内容的提问来源于stack exchange,提问作者Abalo
相关产品推荐
相关产品推荐

