Fortran Coder

查看: 29077|回复: 10

[指针] 关于fortran里指针的讨论

[复制链接]

12

帖子

2

主题

0

精华

入门

F 币
82 元
贡献
43 点
发表于 2014-2-20 00:58:30 | 显示全部楼层 |阅读模式
本帖最后由 btx97 于 2014-2-20 15:53 编辑

因为听说高手都是指针用的比较多的,所以最近在考虑fortran里指针的作用。特意发帖希望高手们能来一起讨论下,让我们学习中的新人长点知识。:lol:lol
在fortran 95/2003 for scientists and engineerings 书中指出,在数组交换的过程中,用指针交换的效率明显比用普通变量交换的效率要高。 所以自己写代码比较了一下效率,代码为
[Fortran] 纯文本查看 复制代码
program test_pointer
  implicit none
  real, dimension(100,100), target :: array1, array2
  real, dimension(:,:), pointer :: p1, p2, temp_p
  real, dimension(100,100) :: a1, a2, temp

  integer :: i
  real :: begin, end

  call random_number(a1)
  call random_number(a2)

  array1=a1
  array2=a2

  p1=>array1
  p2=>array2
  call cpu_time(begin) 
  do i=1,1000000
     temp=a1
     a1=a2
     a2=temp
  end do
  call cpu_time(end)
     
  write(*,*) 'Time of variable exchange:', end-begin

  call cpu_time(begin)
  do i=1,1000000
     temp_p=>p1
     p1=>p2
     p2=>temp_p
  end do
  call cpu_time(end)

  write(*,*) 'Time of pointer exchange:', end-begin

end program test_pointer

运行结果为:

[Shell] 纯文本查看 复制代码
$ ./a.out 
 Time of variable exchange:   4.5159998    
 Time of pointer exchange:  8.00037384E-03




可以发现用指针的确比用普通变量有效。
不过我还有个疑问希望高手能解答下。 fortran中指针所占内存的是不是比它的Target要少很多?  因为如果fortran中指针所占内存跟它的Target一样,那么虽然代码效率是提高了,但所耗资源也提高了不少,就不见得很经济。 

此外,指针在链表里的应用很多书上都讲了。我觉得我们可以先不考虑指针在结构数据的应用。

十分希望各位高手能把自己使用指针的经验体会拿出来分享下, 共同讨论下fortran中指针的优缺点。



709

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
596 元
贡献
305 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

发表于 2014-2-20 09:49:48 | 显示全部楼层
Fortran 的指针具有特殊性。一般来说,所占的内存比它的Target要少很多很多。

if 指向单变量或结构体 then
  在32位编译器里,Fortran指针仅占 4 字节。通常叫 address
else 指向数组或结构体指针 then
  不同编译器会不同。它们会定义一个结构体来描述指向的数组。老外叫 descriptor
endif

单变量就不说了,与 C 的指针是一样的。C++如果不特别处理,指针也是4字节,仅仅表示目标的地址。
指向数组的话,descriptor 大概会是类似这样一个结构体:
Type Pointer_descriptor
  integer Pointer_address !// 这个是与 address 等效的
  integer Array_Dimension !// 数组的维度
  integer Array_Size_Element !// 数组每个元素的大小
  integer ArrayUBound( Array_Dimension ) , ArrayDBound( Array_Dimension ) !// 每个维度的上下限
End Type Pointer_descriptor

这个结构体在源代码中并不存在,Intel Fortran 会采用类似这样的结构来描述一个指向数组的指针。其他编译器会有类似的描述,但不完全相同。

由此可知,指向数组的指针所占的内存,通常在几十字节。如果你指向一个 a(2,2) 的数组,那么指针所占的内存反而比数组本身还大。如果你指向一个 a(100,100) 的数组,那么指针所占的内存就比数组小得多了。

Fortran 的指针,会比 C 的指针占的内存要大一些。

指针交换数组,通常也会比数组直接交换要高效。(注意是通常,上面的可作为反例)
这可以从生活中得到一些类比:

假设两家人,王家住在XX街18号,李家住在XX街9号。现在两家要搬家,各自搬到对方家。(交换房屋)
数组交换就好比:王家把家具床柜子桌子凳子日用品全部搬到临时住处,然后李家把家具床柜子桌子凳子日用品全部搬到王家,最后王家再从临时住处搬到李家。
而指针交换就好比:把18号门牌挂到临时住处,把9号门牌挂到原18号,最后把18号门牌挂到原9号。

显然,指针交换更高效。

Fortran 的指针与 C 的指针差别就是,C 的指针只有地址(门牌号),Fortran 的指针除了地址,还有数组的一些参数,如维度,单元素的大小,各维度上下限(可以类比王家李家的电费余额,水表底数)。

69

帖子

7

主题

0

精华

专家

F 币
320 元
贡献
224 点
发表于 2014-2-20 15:08:21 | 显示全部楼层
Fortran指针是Fortran90标准引进的,之前Fortran中没有指针(编译器扩展除外),所以Fortran77高手基本上不使用指针。

Fortran的强项在于数组操作,所以学习Fortran一定要下功夫学好数组相关的内容。

在Fortran中,指针一般用在一些特殊的场合,比如链表等动态数据结构的实现,与C的互操作以及楼主提到的通过地址操作才能实现高效的少数场合。指针的缺点是容易出现内存泄漏和dangling pointers,因此应用要非常小心。除此之外,可用于可分配数组的一些内部函数也不能用于指针。

1948

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
1298 元
贡献
547 点

美女勋章热心勋章星光勋章新人勋章贡献勋章管理勋章帅哥勋章爱心勋章规矩勋章元老勋章水王勋章

发表于 2014-2-20 15:28:29 | 显示全部楼层
楼上说得没错,严谨和灵活往往不可兼得。

实际上,Fortran 的参数默认是传址的,一定程度上就是指针。所以语法层面上不使用指针也能完成很多事情。

而 C 的参数默认是传值的,如果语法层面上也不使用指针,很多事情就捉襟见肘。

我对指针还是抱有挺乐观的观点的,如果有大量数据的操作,合理应用指针可以提高程序执行效率。

但稍不熟练就容易造成内存里分配了数据,指针都指走了,导致占用内存而且无法使用,如果这样的情况出现在循环里,就是内存泄露,情况就遭了。

12

帖子

2

主题

0

精华

入门

F 币
82 元
贡献
43 点
 楼主| 发表于 2014-2-20 16:12:20 | 显示全部楼层
chuxf 发表于 2014-2-20 09:49
Fortran 的指针具有特殊性。一般来说,所占的内存比它的Target要少很多很多。

if 指向单变量或结构体 then ...

谢谢讲解,又增长了点知识。

这样看来用指针指向大型数组是比较划算的:lol。 

单个变量是不是就不怎么样了,因为一个real好像也是4字节吧。 

另外也谢谢jason388和fcode能说出自己对指针的理解。

1948

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
1298 元
贡献
547 点

美女勋章热心勋章星光勋章新人勋章贡献勋章管理勋章帅哥勋章爱心勋章规矩勋章元老勋章水王勋章

发表于 2014-2-20 17:33:38 | 显示全部楼层
指向单变量的指针也是可以用的。

譬如,以前要相同的处理两个量。需要写两种可能,有了指针,只写一种就可以了。

[Fortran] 纯文本查看 复制代码
real :: rAmp , rPhz
if ( ... )
  call proc( rAmp )
  rAmp = func( rAmp )
  call write( rAmp )
else
  call proc( rPhz )
  rPhz = func( rPhz )
  call write( rPhz )
end if


用指针的话,可以很简单的写为:
[Fortran] 纯文本查看 复制代码
real , target :: rAmp , rPhz
real , pointer :: p
if ( ... )
  p => rAmp
else
  p => rPhz
end if
call proc( p )
p = func( p )
call write( p )


当然了,把那三句话写成子程序,用 rAmp 和 rPhz 分别做参数,也可以。但是相对还是麻烦些

4

帖子

0

主题

0

精华

熟手

F 币
148 元
贡献
72 点
发表于 2014-2-21 10:08:54 | 显示全部楼层
膜拜各位大虾

Fortran还不支持指针数组,不然在数值计算中也可以经常用用的

709

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
596 元
贡献
305 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

发表于 2014-2-21 10:29:51 | 显示全部楼层
delta 发表于 2014-2-21 10:08
膜拜各位大虾

Fortran还不支持指针数组,不然在数值计算中也可以经常用用的 ...

有一个像是“耍赖皮”的方法使用指针数组。

[Fortran] 纯文本查看 复制代码
type pST_Array
  real , pointer :: p( : )
end type pST_Array
Type ( pST_Array) , pointer :: pA( : )
integer :: i , j
Allocate( pA( 10 ) ) !// 产生10个指向数组的指针。
Do i = 1 , 10
  Allocate( pA(i)%p(2) ) !// 每个指针指向一个2元素数组
  Do j = 1 , 2
    pA(i)%p(j) = i*100+j
  End Do
End Do
Do i = 1 , 10
  write( * , * ) pA(i)%p( : )
End Do  
!// 尚未书写释放指针代码
End Program

709

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
596 元
贡献
305 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

发表于 2014-2-21 10:34:00 | 显示全部楼层
这里写 Fortran 代码有个 bug

p(:) 会被替换成表情。得写成 p( : )

12

帖子

2

主题

0

精华

入门

F 币
82 元
贡献
43 点
 楼主| 发表于 2014-2-21 16:33:26 | 显示全部楼层
本帖最后由 btx97 于 2014-2-21 16:37 编辑
delta 发表于 2014-2-21 10:08
膜拜各位大虾

Fortran还不支持指针数组,不然在数值计算中也可以经常用用的 ...

c 语言有指针数组和数组指针的区别,但fotran里好像没有这样的区别吧。

我的例子程序中p1指向了一个数组,这是数组指针的概念的吧。
但p1本身也是个数组,p1(i,j)可以取出所对应的变量值,这个是指针数组的概念吧。

c语言里可以移动一个指针到指定内存单元,如p+1。fortran里好像没这个功能。
而且fortran里也不能拿单个(非数组)指针去指向一个数组。
我哪说错了,你们随便指正哈。学习中,有人指出错误很重要。
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2024-3-29 18:42

Powered by Tencent X3.4

© 2013-2024 Tencent

快速回复 返回顶部 返回列表