2016-06-21 76 views
2

我試圖在Fortran中創建toUpper和toLower函數,並且它們似乎在我的實現中工作正常;程序會提示用戶輸入一個字符串,然後用大寫字母打印出來,然後用小寫字母打印出來。爲什麼我的程序循環兩次?

但是,在我添加一個大寫函數後,程序會提示用戶輸入兩次字符串,但我找不到原因。它似乎工作,但它做了兩次。

有人可以這樣好讓我知道爲什麼我的程序提示輸入兩次?代碼和輸出如下。

program stringutils 
    character :: words*1000 

    print*, 'Enter a string.' 
    read(*,'(A)') words 

    call toUpper(words) 
    print*, 'toUpper: ', trim(words) 

    call toLower(words) 
    print*, 'toLower: ', trim(words) 

    call capitalize(words) 
    print*, 'capitalize: ', trim(words) 

end program stringutils 

subroutine toUpper(string) 
    character :: string*1000 
    integer :: i, charNum 

    do i = 1, len(trim(string)) 
     charNum = iachar(string(i:i)) 
     if (charNum >= 97 .and. charNum <= 122) then 
      string(i:i) = achar(charNum - 32) 
     end if 
    end do 
end subroutine toUpper 

subroutine toLower(string) 
    character :: string*1000 
    integer :: i, charNum 

    do i = 1, len(trim(string)) 
     charNum = iachar(string(i:i)) 
     if (charNum >= 65 .and. charNum <= 90) then 
      string(i:i) = achar(charNum + 32) 
     end if 
    end do 
end subroutine toLower 

subroutine capitalize(string) 
    character :: string*1000 
    integer :: i 

    call toUpper(string(1:1)) 
    do i = 2, len(trim(string)) 
     if (iachar(string(i-1:i-1))==32) then 
      call toUpper(string(i:i)) 
     else 
      call toLower(string(i:i)) 
     end if 
    end do 
end subroutine capitalize 

輸出示例:

Enter a string. 
this IS a tEsT! 
toUpper: THIS IS A TEST! 
toLower: this is a test! 
capitalize: This Is A Test! 
Enter a string. 
why is this running a second time? 
toUpper: WHY IS THIS RUNNING A SECOND TIME? 
toLower: why is this running a second time? 
capitalize: Why Is This Running A Second Time? 

我在Windows中使用gfortran通過MinGW的。

回答

1

這是一個擴展註釋的東西,而不是一個答案......

我不是你的,你最初報告的問題的原因的解釋說服。我不明白爲什麼程序會因爲一個錯誤的例程或兩個而執行兩次。儘管如此,通過對現代Fortran實踐的更多關注,您的例程將大大改善。

你已經寫了一堆例程來處理1000個字符的字符串。更好的辦法是編寫它們來操縱字符串傳遞的任何長度的字符串,因爲參數恰好是。現代的Fortran(因爲當我不知道,至少90%,有可能在此之前)可通過假定長度字符參數,而不是像這樣:

subroutine toUpper(string) 
    character(*) :: string 
    integer :: i, charNum 

    do i = 1, len(trim(string)) 
     charNum = iachar(string(i:i)) 
     if (charNum >= 97 .and. charNum <= 122) then 
      string(i:i) = achar(charNum - 32) 
     end if 
    end do 
end subroutine toUpper 

現在,當程序被調用時,它將運行在string的所有字符中,不多也不少。

還有一些我建議的其他修改。我沒有時間詳細介紹所有這些內容,但如果你在這裏討論,你會在主題中找到幾個問題和答案。這裏有一個初學者集:

  • 總是使用程序實體的明確聲明,包括implicit none在你的程序(和模塊)中。這是編寫安全程序的最基本的規則。
  • 把你的例程放入module s和use他們。這確保了編譯器可以並且確實檢查你對它們所做的調用在語法上是否有效。
  • 就我個人而言,我會將所有subroutines轉換爲functions,並將輸入字符串的一個版本返回到上(或下)情況。有沒有錯,有子程序修改的地方輸入字符串,但它更容易編寫功能,比如你有一天會想要寫的東西像HumpyString = capitalise(toLower(string))
+0

我將子例程轉換爲函數並使用假定的長度字符,但無法編譯。通過靜止的參數具有1000的長度... \t字符(*)FUNCTION TOUPPER(STRING) \t \t字符(*)STRING \t \t整數i \t \t \t DO \t I = 1,LEN (TRIM(STRING)) \t \t \t STRING(I:I)= CHARTOUPPER(STRING(I:I)) \t \t END DO \t END FUNCTION TOUPPER 錯誤:(1)處的字符值內部函數'toupper'不能被假定爲長度。 對不起,我不知道如何格式化。 – nullChar

+0

不要在評論中提問,他們太難閱讀了。 –

0

雖然我不確定是什麼導致它循環兩次,但我知道這是大寫函數的東西,也許我如何發送一個字符到一個函數期望1000個字符。所以我添加了charToUpper和charToLower函數,它現在按預期工作。這是新的代碼。我覺得大寫功能可能會更好......評論歡迎。

program stringutils 
    character words*1000 

    print*, 'Enter a string.' 
    read(*,'(A)') words 

    call toUpper(words) 
    print*, 'toUpper: ', trim(words) 

    call toLower(words) 
    print*, 'toLower: ', trim(words) 

    call capitalize(words) 
    print*, 'capitalize: ', trim(words) 

end program stringutils 

subroutine toUpper(string) 
    character string*1000 
    integer i 

    do i = 1, len(trim(string)) 
     call charToUpper(string(i:i)) 
    end do 
end subroutine toUpper 

subroutine toLower(string) 
    character string*1000 
    integer i 

    do i = 1, len(trim(string)) 
     call charToLower(string(i:i)) 
    end do 
end subroutine toLower 

subroutine charToUpper(c) 
    character c 
    integer charNum 

    charNum = iachar(c) 
    if (charNum >= 97 .and. charNum <= 122) then 
     c = achar(charNum - 32) 
    end if 
end subroutine charToUpper 

subroutine charToLower(c) 
    character c 
    integer charNum 

    charNum = iachar(c) 
    if (charNum >= 65 .and. charNum <= 90) then 
     c = achar(charNum + 32) 
    end if 
end subroutine charToLower 

subroutine capitalize(string) 
    character :: string*1000 
    integer :: i 

    call charToUpper(string(1:1)) 
    do i = 2, len(trim(string)) 
     if (iachar(string(i-1:i-1))==32) then 
      call charToUpper(string(i:i)) 
     else 
      call charToLower(string(i:i)) 
     end if 
    end do 
end subroutine capitalize 
1

我編寫的代碼與Linux中Gfortran。 我遇到以下情況: 您的「循環兩次」問題確實發生過,但並非每次都是我的。我相當隨機地得到了分段錯誤。 我試試回答:

你認爲是正確的,問題來自capitalize子程序。我沒有用gdb調試你的代碼,但seg故障似乎表明你試圖訪問一個未聲明的字符串組件或類似的東西,以及你正在循環調用toUppertoLower的事實。這就是我找到東西的地方:

在循環中,您可以通過發送string(i:i)這是一個唯一字符(長度爲1),致電toUppertoLower。但是,在toUpper中,您聲明瞭長度爲1000的字符,而在此例程中,您僅處理string(i:i),即長度爲1的字符,這不合邏輯。通過將character :: string*1000替換爲character :: string*1,它似乎正在工作,並且它更有意義,因爲此子例程需要每次都轉換一個字符。

我卻無法解釋爲什麼你的代碼崩潰或循環兩次,但它可能是某種內存泄漏爲您的字符長度溢出的結果...

反正@High性能標誌給你一個關於假定長度的角色參數的好建議。編譯器可能已經能夠警告你,如果你已經通過模塊和接口執行參數檢查的方式編碼。也許一個INTENT條款將是明智的。這些是Fortran 90的強大功能。

相關問題