我尝试在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中通过MinGW使用gfortran。
答案 0 :(得分: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
中的所有字符进行操作,不多也不少。
我也建议进行其他一些修改。我没有时间详细介绍它们,但如果你在这里搜索,你会发现几个Q和As主题。这是一套入门套装:
implicit none
。这是编写安全程序的首要原则。module
和use
。这可以确保编译器能够并确实检查您对它们进行的调用是否在语法上有效。subroutines
全部放入functions
并返回一个输入字符串的版本(上面(或下面))。让子程序修改输入字符串没有任何问题,但是编写函数更容易,例如,有一天你可能会想写HumpyString = capitalise(toLower(string))
答案 1 :(得分:1)
我在Linux中使用Gfortran
编译了代码。
我经历了以下几点:
你的&#34;循环两次&#34;问题确实发生了,但不是每次都适合我。我有一个相当随机的分段错误。
我试着回答:
您认为正确,问题来自capitalize
子例程。我无法使用gdb
调试您的代码,但是seg错误似乎表明您试图访问未声明的字符串组件或类似的组件以及您正在调用toUpper
和{ {1}}循环播放。那是我找到的东西:
在循环中,您可以通过发送toLower
来发送toUpper
或toLower
,这是一个唯一字符(长度为1)。但是在string(i:i)
中,您声明了一个长度为1000的字符,而在此例程中,您只处理toUpper
,即长度为1的字符,这不符合逻辑。通过将string(i:i)
替换为character :: string*1000
,它似乎正在工作并且更有意义,因为此子例程每次需要转换一个字符。
我无法解释为什么你的代码崩溃或循环两次但是由于你的字符长度溢出可能会出现某种内存泄漏......
无论如何,@High Performance Mark为您提供了关于假设长度字符参数的好建议。如果编码方式通过模块和接口执行参数检查,编译器可能已经能够警告您。也许一个character :: string*1
条款是明智的。这些是Fortran 90的强大功能。
答案 2 :(得分:0)
虽然我不确定是什么导致它循环两次,但我知道它是大写函数的东西,也许我是如何将一个char发送到期望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