Re: [问题] 变量自行改变

楼主: fragmentwing (片翼碎梦)   2019-09-15 11:03:48
※ 引述《sven1130 (绿色貍猫)》之铭言:
: 如题
: 这个问题困扰我很久了
: 本鲁使用visual studio
: 目前我这个程式的架构
: 是由C++去呼叫一个for的dll
: 然后跑dll里面众多的subroutine
: 重点来了
: 当我跑了六次这个循环的时候
: 在跑完!******************************************
: 标示的该行后
: 有一个于这个循环都没有出现的参数NNE(7)
: 会自动变为一个很奇怪的数字
: 原本为14跑完后变为一个极大的数字
: 但该行甚至这个循环 与参数NNE应该是一点关系也没有
: 为何会这样 求解 先谢过大家了
: 附图
:

: 按一下F11逐步执行后变成
:

: 完全没有道理啊@@
: 附上该循环
: DO I=L,1,-1
: OPEN(60,FILE='MANNING.DAT',STATUS='OLD')
: OPEN(61,FILE='NCCHECH.OUT',STATUS='UNKNOWN')
: READ(60,1002) NC
: 1002 FORMAT(5X,F8.5)
: CMN(I,J)=NC
: !******************************************
: WRITE(61,*)"CMN(",I,",",J,")",CMN(I,J)
: !******************************************
: !将CMN写入NCCHECH.OUT
: READ(IIN,1004) NDS(I,J),XL,XR,LL,LR,LC
: 1004 FORMAT(8X,F8.0,2F8.2,3F8.0)
: C DIST1(I,J)=(LL+LC+LR)/3.0
: DIST1(I,J)=(LL+LC+LR)/3.0*3
: KK=NDS(I,J)
: WRITE(5,1006)J,I,NDS(I,J),XL,XR,DIST1(I,J),CMN(I,J)
: 1006 FORMAT(//5X,I3,2X,I3,4X,F8.0,2X,F8.2,2X,F8.2,2X,F8.2,2X,F8.4)
: READ(IIN,1008)(AY(II,I,J),AX(II,I,J),II=1,KK)
: 1008 FORMAT(2X,F6.2,9F8.2)
: WRITE(5,1978)(AY(II,I,J),AX(II,I,J),II=1,KK)
: 1978 FORMAT(2X,F6.2,9F8.2)
: Z(I,J)=100.0
: DO 1010 II=1,KK
: IF(AX(II,I,J).EQ.XL) N1(I,J)=II
: IF(AX(II,I,J).EQ.XR) N2(I,J)=II
: IF(Z(I,J).GE.AY(II,I,J)) THEN
: Z(I,J)=AY(II,I,J)
: Z919(I,J)=AY(II,I,J)
: END IF
: 1010 CONTINUE
: WRITE(5,1012) N1(I,J),N2(I,J),Z(I,J)
: c WRITE(*,1012) N1(I,J),N2(I,J),Z(I,J)
: 1012 FORMAT(5X,I8,2X,I8,2X,F8.2)
: END DO
经过和认识的工程师讨论后,我确定有某个以FORTRAN开始学的人不会发生
但是从其他语言过来的人可能会没注意到的问题
那就是,FORTRAN的副程式(subroutine)和函式(function)
并不是单纯地call by value而已,call此程式的程式内的变量也会被改变
举个例子:
program main
implicit none
integer :: var
var = 10
call FortranVar(var)
write(*,*) var
stop
end
subroutine FortranVar(var2) !var2就是在FortranVar内的var
implicit none
integer :: var2
var2 = var2**2
return
end
出来的结果会是100,其他程式语言应该会变成10(不变)
看到变量出问题时我有想到这个可能,可是因为这对从FORTRAN开始学的人来说很正常
就忽略这个可能原因了
不过,后来想到当我走出FORTRAN看到别的程式语言都是call by value后很不能接受
所以反过来说,其他语言的使用者在接触到FORTRAN时不知道这点的可能性其实不小
重点是,要注意到这代表所有在副程式和函式内变更的值都会影响回叫出他们的程式
所以有在用Fortran的人,至少我自己在写的时候
只要程式很大,习惯性会写程式码把数值复制下来
放在别的变量后,将原本的变量原封不动地还回去(也就是自己写成call by value)
写了这么多,结论是
我怀疑问题根本是出在那一坨subroutine和function之中
可能需要把程式码复制到word上搜寻有NNE的地方
把每一行有关于NNE的程式码都找出来慢慢看了
作者: sven1130 (绿色貍猫)   2019-09-15 13:37:00
好的 谢谢f大特地回一篇解惑~不过在我的印象之中 NNE这个矩阵是dimension NNE(NE) 而NE我改用在另一个副程式中写入数值(原版用全域常数写死)但NNE这个变量读取的时间与出错的时机 都是在同一个副程式里面@@
楼主: fragmentwing (片翼碎梦)   2019-09-15 14:12:00
等等 你改变写法后 nne有改用allocate 去宣告吗因为照你的说法 好像是延用原本的阵列宣告?但是照理来说 这种方式没有改用动态阵列 编译器不会给过才对好 回去复习以前写的 应该是用(:)或是在副程式内自己宣告parameter也都可 但我不清楚楼主是不是有用后者的写法
作者: sven1130 (绿色貍猫)   2019-09-15 14:40:00
诶这我不大确定耶 近期我把所有东西梳理过一遍 再跟各位先进报告如果是编译的部分 我想dll能生出来 应该就没有问题吧 至少不会出这种错哈哈
作者: blc (Anemos)   2019-09-16 19:59:00
新的fortran可以用intent宣告,不过这有时会有其他问题。
作者: espresso1   2019-09-17 18:14:00
Fortran在传递参数时,是传递这个变量的内存位址Fortran 2003 后如果副程式中的参数加上 VALUE attribuVALUE attribute,则传入数值,而不是位址,上面的例子中主程式中的 var 就不会改变,还是 10一般的情况是 call by reference,改为 call by value
楼主: fragmentwing (片翼碎梦)   2019-09-17 22:41:00
intent90就有 可是那个对于本来的fortran使用方式而言很难搞话说原来到2003都跟别人反著来 别人都特别用指标才传址 就fortran默认传址XD 然后搞得Fortran的指标有点微妙
作者: jubilee2 (3321)   2018-01-30 06:59:00
解决了吗?看起来是IJ过大或是CMN宣告问题
作者: sven1130 (绿色貍猫)   2018-02-18 17:49:00
一直忘记更新 解决了 把很长的程式码切成很多分份就可以了 原因不明@@
作者: yhliu (老怪物)   2018-05-20 08:31:00
FORTRAN 自始应该就是传址的, 而且 Fortran 据说还是最古老的语言. 在 Fortran 77 及以前, 好像也没有 public 变量,Fortran 90 多了很多特性, 不过传址, 变量基本为 local 仍没有变, 只是可以宣告 public 变量. 有些书把 COMMON 区当作 public 变量看待其实是不对的, common 只是位址共用, 其中变量仍要各程式单元宣告. Fortran 的 pointer 有点像python 的变量名称 (所以 python 的程式单元 argument 的传递另成一格,既不是传值也不是传址, 或说有时像传值有时又像传址).

Links booklink

Contact Us: admin [ a t ] ucptt.com