当我尝试运行巨大的Fortran代码(代码是使用英特尔编译器版本13.1.3.192编译)时,它给出了我这样的错误消息:
...
Info[FDFI_Setup]: HPDF code version number is 1.00246
forrtl: severe (153): allocatable array or pointer is not allocated
Image PC Routine Line Source
arts 0000000002AD96BE Unknown Unknown Unknown
arts 0000000002AD8156 Unknown Unknown Unknown
arts 0000000002A87532 Unknown Unknown Unknown
...
尽管如此,如果我在下面的一个子程序中插入一个小的write语句(只是为了检查代码,而不是打扰代码的最初目的)(我无法将所有代码放入,因为它们太大了):
...
endif
call GetInputLine(Unit,line,eof,err)
enddo
if(err) return
! - [elfsummer] 20140815 Checkpoint 23
open(unit = 1, file = '/bin/monitor/log_checkpoint',status='old',position='append')
write(1,*) "BEFORE checking required keys: so far so good!"
close(1)
! check required keys
! for modes = 2,3, P and T are the required keys
if(StrmDat%ModeCI==2.or.StrmDat%ModeCI==3) then
...
然后突然,上面显示的错误消息消失,代码可以正常运行!我还尝试在源代码中的其他位置插入这样的写语句,但上述错误消息仍然存在。
严重(153):未分配可分配的数组或指针 对于$ IOS_INVDEALLOC。当您尝试释放Fortran 90可分配数组或指针时,必须已分配它。您必须先分配数组或指针才能再次释放它。 注意:STAT可以在DEALLOCATE语句中返回此错误。
但是,我没有看到错误和我添加到代码中的“写入语句”之间的任何关系。在我添加写语句的位置没有这样的“allocate”命令。
所以我很困惑。有人知道原因吗?非常感谢任何帮助!!
使用traceback选项,我可以直接找到错误源:
subroutine StringRead(Str,delimiter,StrArray,ns) ! [private] read strings separated by delimiter
implicit none
character*(*),intent(in) :: Str
character*(*),intent(in) :: delimiter
character*(*),pointer :: StrArray(:)
integer,intent(out) :: ns
! - local variables
character(len=len(Str)) :: tline
integer :: nvalue,nvalue_max
character(len=len(StrArray)),pointer:: sarray(:),sarray_bak(:)
integer :: len_a,len_d,i
! deallocate StrArray
if(associated(StrArray)) deallocate(StrArray)
根据追溯给我的信息,错误在于上面显示的最后一个语句。如果我注释掉这个语句,那么“forrtl:severe(153)”错误会在生成新错误时消失......但是,我仍然不认为这个语句本身可能会出错......它就好像它一样只是忽略if ...条件并直接读取deallocate表示,这对我来说似乎很奇怪。
答案 0 :(得分:1)
您可能有一个错误,其中您非法写入内存并损坏存储分配信息的结构。更改代码可能会导致内存损坏发生在其他地方,并且特定错误消失。通常,非法内存访问通常在Fortran中以两种方式发生。 1)非法下标,2)实际和伪参数之间的不匹配,即在调用中的变量和过程中声明的变量之间。您可以使用编译器的运行时下标检查选项来搜索第一种类型的错误。您可以通过将所有过程放在模块中并use
这些模块来防止第二个过程,以便编译器可以检查参数的一致性。
答案 1 :(得分:0)
听起来有些早期的评论给出了一般解释。但是,
1)StrArray(:)是一个Intent(out)吗?也就是说,您是否正在将文件的行读入s / r中的StrArray(),希望将其作为文件的内容返回?如果是这样,请将其声明为(Out)或其应该是什么。
2)为什么StrArray()是指针?它需要是指针吗?如果您想要的只是文件内容,那么使用非指针可能会更好。
您可能仍需要Allocatable或Automatic或其他内容,但在许多情况下非指针更容易。
3)如果必须将StrArray(:)作为指针,则必须在使用前创建其大小/形状等。如果正确定义了调用序列ACTUAL Arg(如果StrArray()是Intent(In)或Intent(InOUT),则可能会这样做。
相反,如果是(Out),则与所有Pointer数组一样,它必须是s / r中的FIRST Allcoated()。
如果早期没有在某处分配,那么它是未定义的,因此DeAllocate()失败,因为它对DeAlloc没有任何内容,因此Stat = 153。
4)您可能希望在不知道要读取的行数的情况下使用它来读取文件。在这种情况下,你不能(至少不容易),提前分配StrArray(),因为你不知道大小。在这种情况下,需要替代策略。
一种可能的解决方案是一个循环,它简单地读取文件中每一行的第一个char或以某种方式前进。让循环跟踪每行读取的“总和”,直到EOF。然后,您将知道文件的大小(以num行为单位),然后分配StrArray(SumLines)或其他东西。像
这样的东西SumLines = 0
Do i=1, ?? (or use a While)
... test to see if "line i" exists, or EOF, if so, Exit
SumLines = SumLines + 1
End Do
最好在单独的s / r中执行此操作,以便在调用FileRead位之前知道Size等(即在FileRead s / r调用之前设置文件大小)。
但是,这仍然会让您遇到使用Character(Len)的问题。有很多可能的解决方案。其中三个是:
a)使用最大长度,如Character(Len = 2048),Intent(Out),或者更好,还有一些编译时常量参数,称之为MaxLineWidth
这对于< = MaxLineWidth的行有明显的限制,并且当有很多“短线”等时内存使用量可能会过大。
b)使用单个char数组,如Character(Len = 1),Intent(Out):: StrArrayChar(:,:)
这是2-D,因为每行中的字符需要1 D,而行的第2个D需要。
与a)相比,它更好一些,因为它可以控制线宽。
c)更通用的方法可能依赖于用户定义类型,例如:
Type MyFileType
Character(Len=1), Allocatable :: FileLine(:) ! this give variable length lines, but each "line" must be allocated to the length of the line
End Type MyFileType
然后,创建此Type的数组,例如:
Type(MyFileType), Allocatable :: MyFile(:) ! or, instead of Allocatable, can use Automatic etc etc
然后,将MyFile分配给Size = num行
...无论如何,有各种各样的选择,每种选择都有适合不同情况的适应性(而且我省略了很多“管家”deAllocs等,你需要实施)。
顺便提一下,c)也是许多Fortran编译器的“可变长度字符串”的一个可能原型,它们不能明确支持。