You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:02:07