【问题标题】:fortran pointer array as returnfortran 指针数组作为返回
【发布时间】:2015-11-04 03:41:51
【问题描述】:

我正在查看一个 Fortran 函数,该函数将(指针)数组返回到固定长度的字符串。像这样的:

FUNCTION F(N)
INTEGER :: N
CHARACTER(LEN=16) :: F(N)

F(1:N) = 'DEFAULT'
...
END FUNCTION F

该函数计算 N 个字符串,据我了解,它会尝试以数组的形式返回这些字符串。

调用者有:

...
ALLOCATE(X(N))
X = F(N)

但是当 F 返回时我得到一个段错误。作者声称他在编译和运行它时没有发现任何问题。我试图了解何时为实际字符串分配内存以及返回后内存是否在范围内?有没有

CHARACTER(LEN=16) :: F(N)

line 分配 N*16 个字符,然后在 F 中分配 N 个指向它们的指针?我来自C所以也许我完全错过了这个,请温柔。 我怀疑F实际指向的内存在返回后没有绑定(我认为它可能在堆栈上等)

感谢任何见解。

【问题讨论】:

    标签: arrays syntax fortran


    【解决方案1】:

    您的函数不返回指针数组,而是返回长度为 16 的字符数组。您可能将返回值分配给 1 级数组字符 (len=16) 的指针或可分配变量,但是这是一个单独的问题。

    返回数组的函数需要显式接口。从您的问题中不清楚是否满足此要求,这可以通过三种方式完成:

    1. 将函数放入模块中(最简单!)
    2. 将函数放在主程序中 contains 语句之后
    3. 为作用域单元中使用的函数编写一个接口块。

    例如:

    module A
    contains
      function f(n)
        implicit none
        integer :: n
        character(len=16) :: f(n)
    
        f(1:n) = 'DEFAULT'
      end function f
    end module A
    
    program test
      use A
      implicit none
      character(len=16), pointer :: array(:)
    
      allocate(array(10))
      array = f(10)
    
      print *, array
    end program test
    

    这会将您的功能放在模块“A”中,只需添加您应该使用的implicit none 语句。与 C 不同,Fortran 允许您在不声明变量的情况下使用变量,并为它们隐式分配类型,当错字创建新变量和调试噩梦时,这会引起丑陋。 implicit none 告诉编译器只使用你声明的变量。

    上例中的主程序将函数的返回值存储在一个指向字符数组的指针中。返回值不仅仅是 N*16 字节,因为与 C 不同,Fortran 字符串包含一些元数据,包括长度(并且不是以空值结尾的)。数组本身将在内部有一个数组描述符,用于存储有关数组边界、维度和一些其他信息的信息,因此总体分配将至少为 N*(16+字符标量开销)+数组描述符长度。引擎盖下的内容比 C 中的要多。

    最后一点要注意,函数f的同名变量f是函数的类型及其返回值。这将在函数返回时在作用域内,并且内存将被复制到分配的array 内存中。作为 C 程序员,您可能遇到的最后一个潜在问题是 Fortran 通过引用传递参数。这在这里不是问题,但如果您假设像 C 那样按值传递,稍后可能会出现这种情况。

    【讨论】:

    • 感谢您抽出宝贵时间发表评论!确实定义了一个我没有显示的接口。我不清楚 ALLOCATE(X(N)) 的目的是什么?我认为数组是由 F 函数分配的。我当然应该证明 X 被声明为 CHARACTER(LEN=16), ALLOCATABLE :: X(:)
    • 分配时的重新分配仅适用于左侧可分配的情况。您的示例使用左侧的指针 - 无论编译器选项如何,都不会应用重新分配分配。
    • @IanH 我把它拿出来了。我最初使用了一个可分配的但更改为一个与 Q 匹配的指针但忘记取出重新分配的东西。感谢您指出。
    • 你们在我头上说话。我现在不知道......你是说代码应该工作吗? Valgrind 抱怨对 F 的调用。我想我将不得不尝试升级我的编译器。
    • 我赞成这个答案,主要是因为它为我指明了正确的方向。我意识到答案并不比问题好多少......所以我找到了一些有用的东西:我将 ALLOCATABLE 更改为 POINTER 并且代码开始工作。现在我只需要更好地了解这里发生了什么。仍然令人费解的是,作者声称他在不同的机器上用 gfortran 和 ifort 编译它,从未见过 segfault。谢谢大家!
    猜你喜欢
    • 2014-07-24
    • 1970-01-01
    • 1970-01-01
    • 2021-08-14
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 2018-03-07
    • 1970-01-01
    相关资源
    最近更新 更多