【问题标题】:Fortran copy of pointer指针的 Fortran 副本
【发布时间】:2016-01-18 11:51:00
【问题描述】:

我有一个类型 var,它包含一个指针 p。 我需要将 var 复制到与 var 相同类型的另一个变量 var1 上(通过做 var1 "=" var,在引号中,因为我不知道这是否正确,见下文)。

在我的实现中 var 和 var1 被传递给一个需要将 var1 初始化为 var 然后修改 var1 的子例程。 如果我改变了 var1%p 的值,那么 var%p 也会被修改。 所以,我需要改变var1%p指向的内存区域的值,而不修改var%p指向的内存区域。 在 Fortran (2003, Intel) 中这样做的正确方法是什么?

代码示例:

type variable 
     real, dimension(:), pointer:: p
end type variable


subroutine init(var,var1) !This of course will not work
  type (variable):: var, var1
  var1=var
end subroutine

现在,我需要能够在不影响 var%p 的情况下执行与更改 var1%p 等价的操作。我无法更改变量(我正在修改现有代码)。


以下解决方案(如果我是正确的): 我将 var1 声明为:

Type(variable), allocatable:: Var1 

然后分配和初始化:

allocate(var1, source=var) 
var1 = var  

然后

call somesub(var1)

修改 var1%p 的结果是修改 var%p 使得 var%p 等于 var1%p。

编辑 3: 正在做:

 subroutine init(var,var1)
 type(variable), intent(in):: var
 type(variable), allocatable, intent(inout):: var1
 allocate(var1%p, source=var%p)
 var1%p = 2 
 end subroutine init

 type variable:: var
 type variable, allocatable:: var1
 call init(var, var1)

以上编译但崩溃(无限挂起)。 改为使用:

allocate(var1, source=var) 

运行但将 var%p 更新为 1。

【问题讨论】:

  • 您是否有一些最少的代码可以展示给我们,以确保我们完全理解您的问题?
  • 我冒昧地猜测一下:您可能最好使用可分配数组来完成您正在尝试做的事情,而不是指针及其目标。如果两个指针指向同一个“内存区域”,那么更改(一个)内存区域的内容当然会影响两个指针指向的内容。您希望指针指向不同的内存区域,尽管可能在关联第二个指针的同时包含相同的内容。但是没有代码真的无法回答你的问题。
  • @HighPerformanceMark 问题已更新

标签: pointers memory fortran


【解决方案1】:

当您对派生类型变量进行内在赋值时,任何指针都会使用指针赋值=> 复制(它只是复制现有内存块的地址和其他属性)。您必须确保在内存中分配了一个新目标,并将数组的值复制到那里。

您可以为给定类型创建自己的重载赋值,然后使用语法var1 = var1,或者您可以将正确的赋值编码到您的子例程中,如果足够的话:

subroutine init(var,var1) !This of course will not work
 type(variable) :: var, var1  !DO NOT FORGET THIS WHEN POSTING EXAMPLES NEXT TIME!

 allocate( var1%p(lbound(var%p,1):ubound(var%p,1)) )

 var1%p = var%p
end subroutine

正如 HighPerformance Mark 评论的那样,如果您没有其他理由使用指针,那么可分配组件会好得多。

type variable 
     real, dimension(:), allocatable :: p
end type variable


subroutine init(var,var1) !This WILL work
  type (variable):: var, var1
  var1 = var
end subroutine

在您的编辑中,您遇到了同样的问题:

var1 = var 

这和之前的问题一模一样,你什么都没改!

还有

allocate(var1, source=var) 

应该和原代码一样的效果,相信你需要

allocate(var1%p, source=var%p) 

但我已经评论说,最常见的 gfortran 版本不会接受这一点,并且需要明确指定形状。

变量varvar1 不必是可分配的。但如果出于其他原因需要,它们也可以。


可以编写一次用户定义的赋值,然后重载内部赋值 (=)。

   type variable
     real :: pointer :: p(:)
   contains
     procedure :: assign
     generic :: assignment(=) => assign
   end type

   subroutine assign(out, in)
      class(variable), intent(out) :: out
      class(variable), intent(in) :: in

      allocate( out%p(lbound(in%p,1):ubound(in%p,1)) )

      out%p = in%p
   end subroutine

然后你可以随时写var1 = var,它会自动调用子程序assign

【讨论】:

  • 我将不得不使用带有指针的解决方案。如果 p 是一个 n 维数组(指向一个指针),是否有更紧凑的方法将 var1%p 分配给 var%p 的大小?
  • 你可以试试allocate(var1, source=var),它几乎不需要子程序。但它确实需要一个最新的编译器。
  • 是的。不幸的是,我使用的 gfortran 版本仍然需要明确指定形状,即使使用 source= 也是如此。我不确定最新版本。
  • 如果数组总是从 1 开始,那么 allocate( var1%p(size(var%p)) ) 会更短。
  • @Henry 当您在源分配上遇到困难时,为什么不直接使用我提供的第一个代码?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多