默认地,fortran程序中调用子程序时,参数传递的是地址,而不是值。这点应该是大家都知道的。既然传递的是地址,那么子程序和主程序中的变量
或数组是不是存储空间是同一段空间呢?这可不一定,要看情况了。为此,写了下面这个简单程序进行测试,目的是在主程序和子程序分别打印数组元素的地址以及
a(1,1)的值的变化:
program main
integer i,j
integer a(10,10)
do i=1,10
do j=1,10
a(i,j)=i*j
enddo
enddo
write(6,*)'The addresses of all the elements of array a:'
do i =1, 10
do j = 1,10
write(6,*)j,i,loc(a(j,i))
enddo
enddo
write(6,*)'The address of a(2,2) in the subroutine:'
call submatrix(a(2,2))
write(6,*)'The addresses of a(1:5,1) in the subroutine:'
a(1,1)=1
call submatrix2(a(1:5,1),5,1)
write(6,*)'a(1,1)=',a(1,1)
write(6,*)'The addresses of a(1:10,1:2) in the subroutine:'
a(1,1)=1
call submatrix2(a(1:10,1:2),10,2)
write(6,*)'a(1,1)=',a(1,1)
write(6,*)'The addresses of a(1:5,1:5) in the subroutine:'
a(1,1)=1
call submatrix2(a(1:5,1:5),5,5)
write(6,*)'a(1,1)=',a(1,1)
end
subroutine submatrix(b)
integer b
write(6,*)2,2,loc(b)
end
subroutine submatrix2(b,m,n)
integer i,j,m,n
integer b(m,n)
do i =1, n
do j =1,m
write(6,*)j,i,loc(b(j,i))
enddo
enddo
b(1,1)=100000
end
运行的结果是:
The addresses of all the elements of array a:
1 1 6446624
2 1 6446628
3 1 6446632
4 1 6446636
5 1 6446640
6 1 6446644
7 1 6446648
8 1 6446652
9 1 6446656
10 1 6446660
1 2 6446664
2 2 6446668
3 2 6446672
4 2 6446676
5 2 6446680
6 2 6446684
7 2 6446688
8 2 6446692
9 2 6446696
10 2 6446700
1 3 6446704
2 3 6446708
3 3 6446712
4 3 6446716
5 3 6446720
6 3 6446724
7 3 6446728
8 3 6446732
9 3 6446736
10 3 6446740
1 4 6446744
2 4 6446748
3 4 6446752
4 4 6446756
5 4 6446760
6 4 6446764
7 4 6446768
8 4 6446772
9 4 6446776
10 4 6446780
1 5 6446784
2 5 6446788
3 5 6446792
4 5 6446796
5 5 6446800
6 5 6446804
7 5 6446808
8 5 6446812
9 5 6446816
10 5 6446820
1 6 6446824
2 6 6446828
3 6 6446832
4 6 6446836
5 6 6446840
6 6 6446844
7 6 6446848
8 6 6446852
9 6 6446856
10 6 6446860
1 7 6446864
2 7 6446868
3 7 6446872
4 7 6446876
5 7 6446880
6 7 6446884
7 7 6446888
8 7 6446892
9 7 6446896
10 7 6446900
1 8 6446904
2 8 6446908
3 8 6446912
4 8 6446916
5 8 6446920
6 8 6446924
7 8 6446928
8 8 6446932
9 8 6446936
10 8 6446940
1 9 6446944
2 9 6446948
3 9 6446952
4 9 6446956
5 9 6446960
6 9 6446964
7 9 6446968
8 9 6446972
9 9 6446976
10 9 6446980
1 10 6446984
2 10 6446988
3 10 6446992
4 10 6446996
5 10 6447000
6 10 6447004
7 10 6447008
8 10 6447012
9 10 6447016
10 10 6447020
The address of a(2,2) in the subroutine:
2 2 6446668
The addresses of a(1:5,1) in the subroutine:
1 1 6446624
2 1 6446628
3 1 6446632
4 1 6446636
5 1 6446640
a(1,1)= 100000
The addresses of a(1:10,1:2) in the subroutine:
1 1 6446624
2 1 6446628
3 1 6446632
4 1 6446636
5 1 6446640
6 1 6446644
7 1 6446648
8 1 6446652
9 1 6446656
10 1 6446660
1 2 6446664
2 2 6446668
3 2 6446672
4 2 6446676
5 2 6446680
6 2 6446684
7 2 6446688
8 2 6446692
9 2 6446696
10 2 6446700
a(1,1)= 100000
The addresses of a(1:5,1:5) in the subroutine:
1 1 193762304
2 1 193762308
3 1 193762312
4 1 193762316
5 1 193762320
1 2 193762324
2 2 193762328
3 2 193762332
4 2 193762336
5 2 193762340
1 3 193762344
2 3 193762348
3 3 193762352
4 3 193762356
5 3 193762360
1 4 193762364
2 4 193762368
3 4 193762372
4 4 193762376
5 4 193762380
1 5 193762384
2 5 193762388
3 5 193762392
4 5 193762396
5 5 193762400
a(1,1)= 100000
结
果说明,如果我只传递一个数组元素如A(2,2)或者连续的一段空间如A(1:5,1)或者A(1:10,1:2),则在主程序中和子程序中的地址是完全
一样的。但如果是不连续的,如A(1:5,1:5),则在主程序和子程序中的地址是不同的。注意我的数组定义的是A(10,10)。 因此,对不连续的情形,似乎主程序和子程序的数组并不在相同的存储空间,而是在子程序里另外开辟了空间,建立了主程序中的地址到子程序中的地址的一个对应。
由于在子程序中改变数组元素的值,主程序中也跟着发生改变(注意看a(1,1)的变化),所以肯定传递的不是值。既然不是值,而数组元素的地址又不一样,
所以只能推断开辟了另一段存储空间,同时主程序和子程序之间的元素地址有一种对应关系,子程序中元素的值发生改变,主程序中对应元素的值也会跟着改变。我
们说开辟了新的存储空间,还有两个证据:1. 在子程序中的数组里,A(1:5,1:5)的25个元素的地址是连续的,在主程序里当然不是连续的;2.
测试表明,在最后一种情形下,即只调用A(1:5,1:5)的情形,你要在子程序里打印A(6,6)的值,得到的是一个不确定的值,给A(6,6)赋值,
在主程序里相应数组元素的值并没有改变。这进一步说明了,在不连续情形下,在子程序里开辟了一段新的存储空间。
所以,结论是,如果调用时
传递的是一段连续的空间,那么不会建立新的数组,如果传递的是不连续的空间,则会建立一个新的数组。在不连续情形下,主程序中相应的元素的值会传递过去,
同时,地址之间也会建立一种对应关系。或者是不是内部建立了一个指针数组,指向的还是主程序中的存储空间。究竟是哪种情况,我也不清楚了。
版权声明,欢迎转载,但必须注明出处。
https://blog.sciencenet.cn/blog-47991-655489.html
上一篇:
PGI编译器如何调用Intel的MKL库下一篇:
调用cula和cublas的一个根本的不同