2013-05-09 17 views
2

我在Fortran語言編寫的這個非常簡單的代碼時:段錯誤調用函數與常量參數

program su 
    implicit none 
    real ran3 
    write(*,*) ran3(0) 
end program su 

real*8 function ran3(iseed) 
    implicit none 
    integer iseed 
    iseed=iseed*153941+1 
    ran3=float(iseed)*2.328+0.5  
end function ran3 

我沒有問題,在編譯,但是當我執行的代碼,我得到這個消息:

Program received signal SIGSEGV: Segmentation fault - invalid memory reference. 

Backtrace for this error: 
#0 0xB76BAC8B 
#1 0xB76BB2DC 
#2 0xB77BA3FF 
#3 0x8048653 in ran3_ 
#4 0x80486B3 in MAIN__ at der.f90:? 
Segmentation fault (core dumped) 

請問爲什麼,我該如何解決?

回答

1

您的代碼沒有做任何事情來告訴聲明

real ran3 

指的是你在你的源文件後定義函數編譯器。對於編譯器,你已經聲明瞭一個名爲ran3的實際變量。一旦編譯器在程序結束時讀取了end聲明,它可以根據需要跳過並喝下mojitos,但它不一定會再編譯 - 儘管您可能會發現有些編譯器會這樣做。

結構化Fortran程序的一般規則是,編譯器在遇到任何使用之前,必須遇到實體(變量,函數,子程序,派生類型,你有什麼)的定義。你的代碼違反了這條規則。

一旦代碼已宣佈它試圖實數變量,在此聲明,

write(*,*) ran3(0) 

訪問數組的第0個元素在淚稱爲ran3和它的所有端部。

快速修復的方法是將end program su移動到源文件的末尾,並在函數的定義之前放入一個包含關鍵字contains的行。然後你可以刪除聲明real ran3,因爲編譯器會處理任何需要完成的鏈接。噢,在我寫作的時候,你可以自己做,也可以試着理解你的代碼,注重格式化你發佈的內容。就個人而言(如果你很容易不高興的話,意見會提出來,現在轉過頭來看看)我會解僱任何代碼翻譯的程序員,理由是任何對這些小東西沒有太多關注的人可能不太關注大東西要麼。

+2

據我瞭解,沒有必要告訴ran3'的'的聲明指的是功能的編譯器。它沒有'dimension'屬性,所以處理器知道它不是一個數組。從參考'ran3(0)'的形式,處理器可以推斷出它是一個函數調用。 – eriktous 2013-05-09 11:21:04

+0

我真的很感謝你的幫助謝謝 – 2013-05-09 15:03:27

5

我看到代碼的兩個問題。第一個是我認爲是錯誤原因的。函數ran3以常量0作爲實際參數引用,但在函數的賦值語句的左側使用相應的僞參數iseed。這是一個錯誤:你不能改變零的值。

第二錯誤是RAN3返回real*8(無論其可以是,它是一個非標準的聲明),而是在主程序ran3被聲明爲是一個默認real

下面的程序和函數用gfortran 4.7.2編譯。

 
program su 
    implicit none 
    real :: ran3 

    write(*, *) ran3(0) 
end program su 

function ran3(iseed) 
    implicit none 
    integer :: iseed, temp 
    real :: ran3 

    temp = iseed * 153941 + 1 
    ran3 = temp * 2.328 + 0.5 
end function ran3 
+0

我非常感謝你的幫助謝謝 – 2013-05-09 14:51:14

+1

我見過這種錯誤實際上「改變零值」的情況。有趣的團隊追查爲什麼在代碼中的其他地方字面零是神祕的不是零。 (很高興它seg錯誤。) – agentp 2016-07-29 14:58:29

1

如果你想,無論出於何種原因,您iseed由函數修改,你應該intent(in out)對它進行標記。如果這樣做,編譯器將在您使用文字常量調用函數時在編譯時觸發錯誤。如果你想使用這個參數作爲輸入,你可以將它標記爲intent(in),並且你將會再次出現一個錯誤,因爲你在函數中分配了iseed。

我認爲這可能是一個好主意,習慣於宣佈意圖。

你的代碼可能看起來像

program su 
    implicit none 

    write(*, *) ran3(0) 

contains 

    function ran3(iseed) 
    implicit none 
    real :: ran3 
    integer, intent(in) :: iseed 
    ! or intent(in out) :: iseed 

    iseed = iseed*153941+1 
    ran3 = float(iseed)*2.328+0.5  
    end function ran3 

end program su 

(如果你使用「在」或「出」的意圖,這將不能編譯,因爲什麼explaned早期不管)。

下反而會編譯(且應該工作,太)

program su 
    implicit none 

    write(*, *) ran3(0) 

contains 

    function ran3(iseed) 
    implicit none 
    real :: ran3 
    integer, intent(in) :: iseed 

    ran3 = real(iseed*153941+1)*2.328+0.5  
    end function ran3 

end program su 
+0

(因爲「爲什麼」在其他地方給出,我沒有考慮它) – ShinTakezou 2013-05-10 09:02:51

+0

非常感謝你 – 2013-05-19 13:24:59

2

雖然有上面做了很多好點,最上面的失敗解決方案功能的直接目的的。值得注意的是,隨機數發生器在許多情況下也需要返回iSeed的「新」值(儘管OP的帖子沒有明確說明),因爲經常在下一次調用Ran s/r時,「新」值iSeed是必需的。

作爲基本規則,常量應該僅作爲參數傳遞給Intent(In)dummy。

從某種意義上說,OP是獲得segv的「幸運兒」,因爲在過去(糟糕的)時代,可以將「number」「0」發送爲「0」,但返回「0 「其他地方都會包含iSeed的價值,並且沒有segv,但是很多算法不好。在這種特定情況下

一個更合適的解決方案將是不通過一個恆定在所有,而是作爲:

program su 
implicit none 
Integer  :: iSeed 
! 
iSeed = 0 ! or whatever iSeed is requried 
! 
write(*, *) ran3(iSeed) 

contains 

    function ran3(iseed) 
     implicit none 
     real :: ran3 
     integer, intent(InOut) :: iSeed 


     iseed = iseed*153941+1 
     ran3 = float(iseed)*2.328+0.5  
    end function ran3 

end program su 

現在,呼叫/使用RAN3的()可以是迭代的,例如通過一個循環或元素等來創建一個(準)隨機序列。

還有其他的可能性使用外部等,但那是另一天。

+0

它canot是元素,Fortran規則禁止'intent(inout)'函數參數爲元素功能。最好把它做成子程序。有人可能會試圖在compund表達式中使用該函數,並且確定像「ran3(iSeed)+ ran3(iSeed)」這樣的正確行爲是非常混亂的。 – 2015-10-29 00:03:48

1

首先您必須將idum定義爲整數。

program su 
    implicit none 
    integer idum 
    real ran3 
    idum = 334 
    write(*,*) ran3(idum) 
    end program su 

那麼你的代碼將工作

+0

注意,即使使用你的補丁,「real」與「real * 8」的問題仍然存在。請參閱前面的答案以獲得詳細的解釋。 – 2016-07-29 10:02:16