作者fragmentwing (片翼碎梦)
看板Fortran
标题Re: [问题] 变数自行改变
时间Sun Sep 15 11:03:48 2019
※ 引述《sven1130 (绿色狸猫)》之铭言:
: 如题
: 这个问题困扰我很久了
: 本鲁使用visual studio
: 目前我这个程式的架构
: 是由C++去呼叫一个for的dll
: 然後跑dll里面众多的subroutine
: 重点来了
: 当我跑了六次这个回圈的时候
: 在跑完!******************************************
: 标示的该行後
: 有一个於这个回圈都没有出现的参数NNE(7)
: 会自动变为一个很奇怪的数字
: 原本为14跑完後变为一个极大的数字
: 但该行甚至这个回圈 与参数NNE应该是一点关系也没有
: 为何会这样 求解 先谢过大家了
: 附图
: https://imgur.com/7kf4X9E
: 按一下F11逐步执行後变成
: https://imgur.com/gznxEKU
: 完全没有道理啊@@
: 附上该回圈
: 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的程式码都找出来慢慢看了
--
即使祂每天因人们而堕入滚烫的热水,面神也不会制造出地狱来惩罚不信仰祂的人
我们崇拜面神是出於敬佩与感谢,与生前死後诸利益得失皆无任何关系
阿面~
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 42.77.1.161 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/Fortran/M.1568516631.A.2F8.html
※ 编辑: fragmentwing (42.77.1.161 台湾), 09/15/2019 11:14:53
※ 编辑: fragmentwing (42.77.1.161 台湾), 09/15/2019 11:17:37
1F:推 sven1130: 好的 谢谢f大特地回一篇解惑~ 09/15 13:37
2F:推 sven1130: 不过在我的印象之中 NNE这个矩阵是dimension NNE(NE) 而 09/15 13:50
3F:→ sven1130: NE我改用在另一个副程式中写入数值(原版用全域常数写死) 09/15 13:50
4F:→ sven1130: 但NNE这个变数读取的时间与出错的时机 都是在同一个副 09/15 13:50
5F:→ sven1130: 程式里面@@ 09/15 13:50
6F:→ fragmentwing: 等等 你改变写法後 nne有改用allocate 去宣告吗 09/15 14:12
7F:→ fragmentwing: 因为照你的说法 好像是延用原本的阵列宣告? 09/15 14:12
8F:→ fragmentwing: 但是照理来说 这种方式没有改用动态阵列 编译器不会 09/15 14:14
9F:→ fragmentwing: 给过才对 09/15 14:14
10F:→ fragmentwing: 好 回去复习以前写的 应该是用(:)或是在副程式内自 09/15 14:27
11F:→ fragmentwing: 己宣告parameter也都可 但我不清楚楼主是不是有用後 09/15 14:27
12F:→ fragmentwing: 者的写法 09/15 14:27
13F:推 sven1130: 诶这我不大确定耶 近期我把所有东西梳理过一遍 再跟各位 09/15 14:40
14F:→ sven1130: 先进报告 09/15 14:40
15F:→ sven1130: 如果是编译的部分 我想dll能生出来 应该就没有问题吧 至 09/15 14:40
16F:→ sven1130: 少不会出这种错哈哈 09/15 14:40
17F:→ blc: 新的fortran可以用intent宣告,不过这有时会有其他问题。 09/16 19:59
18F:推 espresso1: Fortran在传递参数时,是传递这个变数的记忆体位址 09/17 18:14
19F:推 espresso1: Fortran 2003 後如果副程式中的参数加上 VALUE attribu 09/17 18:26
20F:→ espresso1: VALUE attribute,则传入数值,而不是位址, 09/17 18:27
21F:→ espresso1: 上面的例子中主程式中的 var 就不会改变,还是 10 09/17 18:27
22F:推 espresso1: 一般的情况是 call by reference,改为 call by value 09/17 18:33
23F:→ fragmentwing: intent90就有 可是那个对於本来的fortran使用方式而 09/17 22:41
24F:→ fragmentwing: 言很难搞 09/17 22:41
25F:→ fragmentwing: 话说原来到2003都跟别人反着来 别人都特别用指标才 09/17 22:43
26F:→ fragmentwing: 传址 就fortran预设传址XD 然後搞得Fortran的指标有 09/17 22:43
27F:→ fragmentwing: 点微妙 09/17 22:43
28F:→ jubilee2: 解决了吗?看起来是IJ过大或是CMN宣告问题 01/30 06:59
29F:推 sven1130: 一直忘记更新 解决了 把很长的程式码切成很多分份就可以 02/18 17:49
30F:→ sven1130: 了 原因不明@@ 02/18 17:49
31F:→ yhliu: FORTRAN 自始应该就是传址的, 而且 Fortran 据说还是最古老 05/20 08:31
32F:→ yhliu: 的语言. 在 Fortran 77 及以前, 好像也没有 public 变数, 05/20 08:33
33F:→ yhliu: Fortran 90 多了很多特性, 不过传址, 变数基本为 local 仍 05/20 08:35
34F:→ yhliu: 没有变, 只是可以宣告 public 变数. 有些书把 COMMON 区当 05/20 08:36
35F:→ yhliu: 作 public 变数看待其实是不对的, common 只是位址共用, 其 05/20 08:38
36F:→ yhliu: 中变数仍要各程式单元宣告. Fortran 的 pointer 有点像 05/20 08:40
37F:→ yhliu: python 的变数名称 (所以 python 的程式单元 argument 的传 05/20 08:41
38F:→ yhliu: 递另成一格,既不是传值也不是传址, 或说有时像传值有时又像 05/20 08:43
39F:→ yhliu: 传址). 05/20 08:44