Re: [問題] 變數自行改變

作者: fragmentwing (片翼碎夢)   2019-09-15 11:03:48
※ 引述《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的程式碼都找出來慢慢看了
作者: 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