Fortran Coder

标题: Fortran 主程序 如何取出 子程序里面的 数组,多谢多谢 [打印本页]

作者: nsnmb    时间: 2016-1-12 15:40
标题: Fortran 主程序 如何取出 子程序里面的 数组,多谢多谢
各位大牛,小弟期望能实现这样一个功能:
1. 在子程序里面读取一个文件(20+行,每行1个整数),并且把这20+个整数放入一个数组中,比如该数组名字为elem(:)。由于在读取之前不知道有几个元素,因此在子程序里面,定义elem(:)为动态数组。
2. 在子程序里面已经把elem做好,在主程序里面,如何调用该数组呢。

如果按照如下程序,则提示 forrtl: severe (174): SIGSEGV, segmentation fault occurred
错误的原因在于两次定义了allocatable 变量elem, 可是,如果不这么做,该怎么把子程序里面的elem(:)传回主程序呢?
[Fortran] 纯文本查看 复制代码
       program main
       integer, allocatable :: elem(:)
c
        call assem(elem)
c
        end
c--------------------------------------------------------------------------
c--------------------------------------------------------------------------
       subroutine assem(elem)
       implicit none
       character(Len=100)  tmp_str(1000)
       integer,allocatable :: elem(:)
       integer I,J
       open(11,file='data.txt',status=old)
c--------------------------------------------------------------------------
c      put the whole file into memory as character ...starts
c--------------------------------------------------------------------------      
        J = 0
        do I = 1,4000
          read(11,'(a)',end=101) tmp_str(I)
          J = J +1
101  enddo
c
       allocate(elem(J))
c
c--------------------------------------------------------------------------
c      put the whole file into memory as character ...completed
c--------------------------------------------------------------------------   
c
c--------------------------------------------------------------------------
c      put the data into array elem(:) ...starts
c--------------------------------------------------------------------------     
c    do I = 1,J
       read( tmp_str(I),*)elem(I)
      enddo
c--------------------------------------------------------------------------
c      put the data into array elem(:) ...completed
c--------------------------------------------------------------------------     
      end

作者: pasuka    时间: 2016-1-12 16:21
1、为啥不使用module呢?
2、为啥不在allocate之前,调用allocated函数做判断呢?
作者: fcode    时间: 2016-1-12 19:20
子程序和主程序彼此独立,想交换数据,可通过:a. 传递参数  b.使用 common,c. 使用 module(任选其一)
但你的问题,更好的方法是,先获得文件大小,分配以后再读取。不推荐你先用字符串读入,因为 1000 的字符串可能浪费,也可能不够。字符串100的长度也可能浪费,也可能不够。
以下代码使用了一个叫 GetFileN 的函数,这个函数已经写好了,你以后可以直接使用。(更多请参考:http://fcode.cn/code_gen-34-1.html
[Fortran] 纯文本查看 复制代码
Module DFile_Mod
  Implicit None
  
contains
  
  Integer Function GetFileN( iFileUnit )
    Implicit None
    Integer , Intent( IN ) :: iFileUnit
    character( Len = 1 ) :: cDummy
    integer :: ierr
    GetFileN = 0
    Rewind( iFileUnit )
    Do
      Read( iFileUnit , * , ioStat = ierr ) cDummy
      If( ierr /= 0 ) Exit
      GetFileN = GetFileN + 1
    End Do
    Rewind( iFileUnit )
  End Function GetFileN

End Module DFile_Mod

Program main
  use DFile_Mod
  Implicit none
  Integer, Allocatable :: elem(:)
  Integer :: N
  Open (11, File='data.txt', Status='old')
  N = GetFileN( 11 )
  Allocate( elem(N) )
  Call assem( 11 , elem )
  Write (*, *) elem
  Deallocate( elem )
  Close( 11 )
contains
  Subroutine assem( FILEID , elem )
    Integer :: elem(:) , FILEID , i
    Do i = 1, size(elem)
      Read ( FILEID , * ) elem(i)
    End Do
  End Subroutine assem
End Program main

作者: nsnmb    时间: 2016-1-13 14:22
本帖最后由 nsnmb 于 2016-1-13 14:36 编辑
pasuka 发表于 2016-1-12 16:21
1、为啥不使用module呢?
2、为啥不在allocate之前,调用allocated函数做判断呢? ...

多谢多谢!昨天晚上做梦还在想如何用modulu来实现呢。
只是还搞不定如何用modulue来实现(文件如果有可能的话读一遍?)。
还望您再次给点提携呀:).

作者: nsnmb    时间: 2016-1-13 14:34
fcode 发表于 2016-1-12 19:20
子程序和主程序彼此独立,想交换数据,可通过:a. 传递参数  b.使用 common,c. 使用 module(任选其一)
...

非常感谢您负责任的指导!非常感谢!
1. 采用这个方法解决了我面临的困难,我暂时先这么用着:)。
2. 是否可以,目标文件只读一遍?要是我这个文件有很多行,比如接近300万行(目前碰到的是这么多行),我恐怕读两遍会影响将来程序的运行速度。
3. 据说是采用指针变量的话主程序和子程序可以通用一个变量,在子程序里面定义的动态变量回到主程序后不会被deallocate掉,可是还不知道具体怎么操作。
作者: fcode    时间: 2016-1-13 18:19
1.代码中的 module 只是为了避免书写 interface 接口,并无其他用处。不能避免读两次,也不能产生数据共享。
2.你的问题其实是如何读取未知行数的文件,而非“如何在主程序和子程序间共享数据
3.如果你要解决如何在主程序和子程序间共享数据,那么可以使用 : a. 传递参数  b.使用 common,c. 使用 module(任选其一) 不需要使用指针。
4.如果你要解决如何读取未知行数的文件,那么方法1,是使用我的办法,读2次。方法2,是使用指针串表。但这样对数组的访问效率不高。
5.如果您的数据文件,每行的长度是确定的。那么还可以通过文件大小除以每行的长度来获得文件行数。
作者: nsnmb    时间: 2016-1-15 15:04
fcode 发表于 2016-1-13 18:19
1.代码中的 module 只是为了避免书写 interface 接口,并无其他用处。不能避免读两次,也不能产生数据共享 ...

多谢多谢啦!
我这个程序用于求解声场的近似核姆霍兹积分,算是一个求解器。因此速度上面还是希望尽量快一点。
采用子程序后,单元和节点的组装放在里面,很干净,主程序直接读就可以了。可是这样的问题就是要读两遍,而声速度文件巨大无比,30000个节点,每个节点3个方向速度,还有频率至少有1000个频率点,这些数据乘起来文件的行数就是~100,000,000了,此外,还有虚部实部的问题,因此,我最后把他们放在同一个程序里面了。这样比较快些。
多谢多谢啦!




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2