Fortran Coder
标题: 数组指针参数在返回时为什么改变了指向的数据? [打印本页]
作者: linpo 时间: 2018-11-24 00:20
标题: 数组指针参数在返回时为什么改变了指向的数据?
一个过程的一个参数是一个数组指针。
这个指针在过程内被正确赋值,可通过PRINT打印语句证明。但当过程调用结束后,它的值就变化了,实在不明所以,请大神指教。
下面是完整的、可编译的代码:
[Fortran] 纯文本查看 复制代码
SUBROUTINE BIANXING(data_2d, data_1d, nrow, ncol)
implicit none
REAL, DIMENSION(:,:), POINTER, INTENT(INOUT) :: data_2d
REAL, DIMENSION(:), POINTER, INTENT(IN) :: data_1d
INTEGER, INTENT(IN) :: nrow
INTEGER, INTENT(IN) :: ncol
INTEGER i
DO i=1, nrow
! PRINT *, "i=", i, 1+(i-1)*ncol, i*ncol
data_2d(i:i, 1:ncol) => data_1d(1+(i-1)*ncol : (i-1)*ncol+ncol)
PRINT *, data_2d(i:i, 1:ncol)
END DO
END SUBROUTINE BIANXING
PROGRAM MAIN
implicit none
INTERFACE
SUBROUTINE BIANXING(data_2d, data_1d, nrow, ncol)
implicit none
REAL, DIMENSION(:,:), POINTER, INTENT(INOUT) :: data_2d
REAL, DIMENSION(:), POINTER, INTENT(IN) :: data_1d
INTEGER, INTENT(IN) :: nrow
INTEGER, INTENT(IN) :: ncol
END SUBROUTINE BIANXING
END INTERFACE
REAL, DIMENSION(12), TARGET :: arr
REAL, DIMENSION(:), POINTER :: p_1d
REAL, DIMENSION(:, :), POINTER :: p_2d
INTEGER :: i
arr = (/1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12/)
p_1d => arr
call BIANXING(p_2d, p_1d, 3, 4)
PRINT *, "===================================="
DO i=1, 3
PRINT *, p_2d(i, 1:4)
END DO
END PROGRAM MAIN
屏幕显示的结果是:
1.00000000 2.00000000 3.00000000 4.00000000
5.00000000 6.00000000 7.00000000 8.00000000
9.00000000 10.0000000 11.0000000 12.0000000
====================================
7.00000000 8.00000000 9.00000000 10.0000000
8.00000000 9.00000000 10.0000000 11.0000000
9.00000000 10.0000000 11.0000000 12.0000000
那一连串等号上面的数字是在过程内部打印出来的,下面是在调用过程之后打印出来了。我期待的结果应该两者相同啊。请问问题出在哪里?
多谢!
作者: li913 时间: 2018-11-26 10:17
1、运行会报错,等号下面的不能输出,角标越界。
2、fortran的指针只能作为一个整体去执行“指向”操作,data_2d(i:i, 1:ncol) => data_1d(1+(i-1)*ncol : (i-1)*ncol+ncol) 这一句的意思是 data_2d的第一个角标上下限都是i,第二个角标1:到4 。重复3次后,最终相当于data_2d(3:3,1:4)这样一个数组。因此第二次输出会导致越界。
[Fortran] 纯文本查看 复制代码
SUBROUTINE BIANXING(data_2d, data_1d, nrow, ncol)
implicit none
REAL, DIMENSION(:,:), POINTER, INTENT(INOUT) :: data_2d
REAL, DIMENSION(:), POINTER, INTENT(IN) :: data_1d
INTEGER, INTENT(IN) :: nrow
INTEGER, INTENT(IN) :: ncol
data_2d(1:ncol,1:nrow) => data_1d
write(*,"(4f6.1)") data_2d
END SUBROUTINE BIANXING
PROGRAM MAIN
implicit none
INTERFACE
SUBROUTINE BIANXING(data_2d, data_1d, nrow, ncol)
implicit none
REAL, DIMENSION(:,:), POINTER, INTENT(INOUT) :: data_2d
REAL, DIMENSION(:), POINTER, INTENT(IN) :: data_1d
INTEGER, INTENT(IN) :: nrow
INTEGER, INTENT(IN) :: ncol
END SUBROUTINE BIANXING
END INTERFACE
REAL, DIMENSION(12), TARGET :: arr
REAL, DIMENSION(:), POINTER :: p_1d
REAL, DIMENSION(:, :), POINTER :: p_2d
INTEGER :: i
arr = (/1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12/)
p_1d => arr
call BIANXING(p_2d, p_1d, 3, 4)
PRINT *, "===================================="
write(*,"(4f6.1)") p_2d
END PROGRAM MAIN
作者: vvt 时间: 2018-11-26 11:18
fortran的指针并不能实现:一部分指向A,一部分指向B
所以,当你
DO i=1, nrow
data_2d(i:i, 1:ncol) => data_1d(1+(i-1)*ncol : (i-1)*ncol+ncol)
END DO
这个循环第k次的时候,data_2d 的大小就变成了 data_2d(k:k,:) ,大小是 1*ncol ,而不是 k*ncol
你可以用下面的方法,实现把一个二维数组指针,指向一维数组。
[Fortran] 纯文本查看 复制代码
PROGRAM MAIN
use , intrinsic :: ISO_C_Binding
implicit none
REAL, DIMENSION(12), TARGET :: arr
REAL, DIMENSION(:, :), POINTER :: p_2d
INTEGER :: i
arr = (/1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12/)
call c_f_pointer( c_loc(arr) , p_2d , [3,4])
PRINT *, "===================================="
DO i=1, 3
PRINT *, p_2d(i, :)
END DO
END PROGRAM MAIN
作者: linpo 时间: 2018-11-27 16:08
非常感谢 vvt 和 li913! 我是从c和python转过来的,非常不适应Fortran的指针。熬夜学习了还是不能改变原来的惯性思维,多谢两位的点拨!
总结一下我的错误:
1. 误以为 dimension(:,:), pointer 声明的是由指针组成的数组。Fortran根本没有指针数组,只有可以指向数组的单个指针。
2. 指向数组的指针在赋值时确实只能作为一个整体进行赋值。(引用时可以指定下标,因为Fortran的指针就是目标的别名嘛。这是另一回事了。)
作者: fcode 时间: 2018-11-28 08:22
如果你用过 C++,那么 fortran 的指针其实就是 C++ 的 “智能指针” 的一种。
你想要指针数组,可以这样
[Fortran] 纯文本查看 复制代码
type :: pArr
real , pointer :: x(:)
end type pA
type( pArr ) :: p(30)
欢迎光临 Fortran Coder (http://bbs.fcode.cn/) |
Powered by Discuz! X3.2 |