Fortran:变量自行改变

时间:2013-06-12 19:17:14

标签: fortran fortran77

我遇到了变量被覆盖的问题,我不知道是什么原因。我已经在下面发布了一大块代码,以便您可以看到事情是如何声明的。变量strain,Qi,Qf,Qd,tel和Gc被传递到子程序并用于计算ssgrad,strn0,strss0。

我的问题是tel和Gc被传递到子例程OK但是由于某种原因在这段代码中改变了值。

使用print语句我发现问题首先发生在第二次执行循环期间。当我将strss0设置为0时,Gc和tel将两者的值从等于1变为看似随机的数字:tel = 11.52822 Gc = -8.789086(仅为示例所示)

每次运行代码时,它们都被设置为相同的值。

只是为了通知您,此子程序与商业有限元包接口。

非常感谢您提供任何帮助

subroutine initcalcs(strain,Qi,Qf,Qd,tel,Gc,ssgrad,strn0,strss0)

  implicit none

  integer :: i,j

  real*8:: nstrn0,nstrs0,strn0,strnf,varsq,normvar,lmbda0,lmbdaf,
 # ssgrad,t0,tt,tel,nstrnf,nstrsf,Gc

  real*8, dimension(3) :: strain,stran0,stranf,strss0,strssf,var

  real*8, dimension(3,3) :: Qd,Qi,Qf


  lmbda0=1.0d0                                                                                          


  nstrn0=0.0d0                                                                             
  do i=1,3
        stran0(i)=0.0d0
        stran0(i)=strain(i)*lmbda0                                                         
        nstrn0=nstrn0+stran0(i)**2                                                         
  end do                                                                                    

  nstrn0=dsqrt(nstrn0)                                                                     


  do i=1,3
        strss0(i)=0.0d0 
  end do

2 个答案:

答案 0 :(得分:3)

在Fortran中,内存值损坏有两个常见原因。一个是下标错误,您使用不正确的下标值分配给数组元素。这将写入阵列外部的内存位置。另一个是对过程(子例程或函数)的调用中的参数与过程的伪参数之间的不一致。两者都可能导致问题出现在与实际原因不同的源代码位置。建议:检查代码是否存在这些问题。打开编译器的严格警告和错误检查选项。使用Fortran> = 90和模块可以让Fortran更好地自动查找参数一致性问题。您可以使用调试器监视内存位置,并查看它修改它的内容。

答案 1 :(得分:1)

我同意M. S. B。:打开严格的警告和错误检查,并验证子例程调用是否传递与子例程所期望的类型和形状(数组维度)相同的参数。

变量声明语法中的冒号暗示这是Fortran90或更高版本。如果是这种情况,我强烈建议使用INTENT修饰符来指定参数是否只读。

例如,让我们假设传递给此例程的参数,strainQiQfQdtelGc是只读输入,参数为ssgradstrn0strss0作为输出返回;也就是说,无论它们有什么价值都会被这个例程所覆盖。

参数的变量声明将更改为:

real*8, dimension(3), intent(in) :: strain
real*8, dimension(3,3), intent(in) :: Qi, Qf, Qd
real*8, intent(in) :: tel, Gc

real*8, intent(out) :: strn0, ssgrad 
real*8, dimension(3), intent(out) :: strss0

INTENT关键字是对Fortran 90的补充,它允许用户指定哪些参数是只读的(INTENT(IN)),已初始化但可在例程中修改({{1} }),它们被视为未初始化,将在例程(INTENT(INOUT))中设置。

如果未指定INTENT(OUT),则默认为INTENT,这与FORTRAN 77一致(请注意,未指定INOUTINTENT(INOUT)之间存在细微差别但它们在这个例子中并不相关。)

如果例程尝试将值赋给声明为INTENT的变量,则良好的编译器将抛出错误,并且如果声明INTENT(IN)的变量未被赋值,则至少会发出警告价值。

如果可能,在所有应该是只读的变量上设置INTENT(OUT)。这可能是不可能的,这取决于这些变量如何传递给其他例程。如果在此例程中调用的例程的参数上未指定INTENT(IN),则默认为INTENT。如果将INOUT变量作为INTENT(IN)参数传递,编译器将抛出错误。如果在您控制的代码中发生这种情况,则必须在许多例程中指定INTENT(INOUT)。这可能是也可能不合适,这取决于您是否希望一般地改进代码或者只是快速解决这个问题。

我假设这些变量中的一些传递给有限元包中的外部例程,我猜测它是与你的代码相关联而不是编译的;我不确定在这种情况下如何处理编译时意图检查。