fortran90中的动态数组分配

时间:2014-12-11 07:02:21

标签: fortran dynamic-arrays

我正在fortran90中编写一个通用子程序,它将读入一列数据(实际值)。子程序应首先检查文件是否存在并且可以打开,然后通过读取行​​数直到文件末尾来确定列中的元素数(Array_Size)。接下来,子例程将文件重新回到开头并读入数据点并将每个数据分配给一个数组(Column1(n)),并确定数组中的最大元素(Max_Value)。希望这个子程序可以写成完全通用的,不需要事先知道文件中数据点的数量,这就是为什么元素的数量首先被确定为数组," Column1&#34 ;,可以动态分配包含" Array_Size"数据点数。将数组传递给主程序后,它将被传输到另一个数组,并且释放初始动态分配的数组,以便可以为多个其他输入文件重复该例程,尽管此示例仅读取一个数据文件。

如下所示,该程序在英特尔fortran编译器上编译得很好;然而,当它运行时,它给我一个严重的(174):SIGSEV故障。我在子例程中的allocate语句之前和之后放置了write()语句,它打印出第一个语句"程序在这里工作",但不是第二个,表示问题发生在两个write()语句之间的ALLOCATE(Column1(Array_Size))语句中。我使用-C标志重新编译它并运行可执行文件,它再次失败并指出严重(408):"当未分配"时尝试从可分配变量MISC_ARRAY获取。变量MISC_ARRAY是主程序中的虚拟变量,它似乎表明编译器需要在主程序中而不是在子程序中分配的数组。如果我静态分配数组,程序工作正常。为了使程序通用并且不需要知道每个文件的大小,它需要动态分配,这应该发生在子程序中,而不是主程序中。有没有办法实现这一点,我没有看到?

         PROGRAM MAIN
         IMPLICIT NONE
  ! - variable Definitions for MAIN program
         INTEGER :: n
  ! - Variable Definitions for EXPENSE READER Subprograms
         REAL, DIMENSION(:), ALLOCATABLE :: Misc_Array,MISC_DATA
         INTEGER :: Size_Misc
         REAL :: Peak_Misc_Value
  !       REAL :: Misc_Array(365)
         CHARACTER(LEN=13) :: File_Name
        File_Name = "Misc.txt"
        CALL One_Column(File_Name,Size_Misc,Peak_Misc_Value,Misc_Array)
        ALLOCATE (MISC_DATA(Size_Misc))
        DO n = 1,Size_Misc ! Transfers array data
         MISC_DATA(n) = Misc_Array(n)
        END DO
        DEALLOCATE (Misc_Array)
        END PROGRAM MAIN

        SUBROUTINE One_Column(File_Name,Array_Size,Max_Value,Column1)

        IMPLICIT NONE
        REAL, DIMENSION(:), ALLOCATABLE,INTENT(OUT) :: Column1
   !     REAL :: Column1(365)
        REAL, INTENT(OUT) :: Max_Value
        CHARACTER,INTENT(IN) :: File_Name*13
        INTEGER, INTENT(OUT) :: Array_Size
        INTEGER :: Open_Status,Input_Status,n

   ! Open the file and check to ensure it is properly opened
        OPEN(UNIT=100,FILE = File_Name,STATUS = 'old',ACTION = 'READ', &
             IOSTAT = Open_Status)
        IF(Open_Status > 0) THEN
         WRITE(*,'(A,A)') "**** Cannot Open ",File_Name
         STOP
         RETURN
        END IF
   ! Determine the size of the file
        Array_Size = 0
        DO 300
        READ(100,*,IOSTAT = Input_Status)
        IF(Input_Status < 0) EXIT
        Array_Size = Array_Size + 1
   300  CONTINUE
        REWIND(100)
        WRITE(*,*) "Program works here"
        ALLOCATE (Column1(Array_Size))
        WRITE(*,*) "Program stops working here"
        Max_Value = 0.0
        DO n = 1,Array_Size
         READ(100,*) Column1(n)
         IF(Column1(n) .GT. Max_Value) Max_Value = Column1(n)
        END DO
        END SUBROUTINE One_Column

2 个答案:

答案 0 :(得分:3)

这是一个有根据的猜测:我认为子例程One_Column应该有一个显式接口。如上所述,源代码有2个编译单元,一个程序(称为main)和一个外部子程序(称为One_Column)。

在编译时,编译器无法找出从程序中调用子例程的正确方法。在古老的(强调旧的)Fortran风格中,它需要一个信念的飞跃,并将其留给链接器以找到具有正确名称的子例程并交叉其手指(原样)并希望实际参数与伪参数匹配在运行时。这种方法不会对返回已分配数据结构的子程序起作用。

对于简单的修复移动end program到源文件的末尾,在空出的行中输入关键字contains。然后编译器将负责创建必要的接口。

要获得更具伸缩性的修复,请将子例程放入module并使用 - 关联它。

答案 1 :(得分:0)

我认为显示更正的代码非常重要,以便将来的用户可以阅读问题并查看解决方案。我将子程序分解为一系列较小的函数和一个子程序,以使数据尽可能保持本地化,并将其实现为模块。主程序和模块附后。主程序包括对函数的调用两次,只是为了表明它可以模块化地用于打开多个文件。

          PROGRAM MAIN
   !
   !  - Author:  Jonathan A. Webb
   !  - Date:    December 11, 2014
   !  - Purpose: This code calls subprograms in module READ_COLUMNAR_FILE
   !             to determine the number of elements in an input file, the 
   !             largest element in the input file and reads in the column of
   !             data as an allocatable array
   !***************************************************************************
   !***************************************************************************
   !*********************                                **********************
   !*********************      VARIABLE DEFINITIONS      **********************
   !*********************                                **********************
   !***************************************************************************
   !***************************************************************************
          USE READ_COLUMNAR_FILE
          IMPLICIT NONE
          CHARACTER(LEN=13) :: File_Name
          INTEGER :: Size_Misc,Size_Bar,Unit_Number
          REAL :: Peak_Misc_Value,Peak_Bar_Value
          REAL, DIMENSION(:), ALLOCATABLE :: Misc_Array,Bar_Array
   !***************************************************************************
   !***************************************************************************
   !*********************                                **********************
   !*********************        FILE READER BLOCK       **********************
   !*********************                                **********************
   !***************************************************************************
   !***************************************************************************
   ! - This section reads in data from all of the columnar input decks.

        ! User defines the input file name and number
          File_Name = "Misc.txt"; Unit_Number = 100
        ! Determines the number of rows in the file
          Size_Misc = File_Length(File_Name,Unit_Number)
        ! Yields the allocatable array and the largest element in the array
          CALL Read_File(File_Name,Unit_Number,Misc_Array,Peak_Misc_Value)

          File_Name = "Bar.txt"; Unit_Number = 100
          Size_Bar = File_Length(File_Name,Unit_Number)
          CALL Read_File(File_Name,Unit_Number,Bar_Array,Peak_Bar_Value)

          END PROGRAM MAIN

          MODULE READ_COLUMNAR_FILE
   !***********************************************************************************
   !***********************************************************************************
   !                                                                                ***
   !  Author:        Jonathan A. Webb                                               ***
   !  Purpose:       Compilation of subprograms required to read in multi-column    ***
   !                 data files                                                     ***
   !  Drafted:       December 11, 2014                                              ***
   !                                                                                ***
   !***********************************************************************************
   !***********************************************************************************
   !
   !-----------------------------------
   ! Public functions and subroutines for this module
   !-----------------------------------
          PUBLIC :: Read_File
          PUBLIC :: File_Length
   !-----------------------------------
   ! Private functions and subroutines for this module
   !-----------------------------------
          PRIVATE :: Check_File
   !===============================================================================
          CONTAINS
   !===============================================================================
          SUBROUTINE Check_File(Unit_Number,Open_Status,File_Name)
          INTEGER,INTENT(IN) :: Unit_Number
          CHARACTER(LEN=13), INTENT(IN) :: File_Name
          INTEGER,INTENT(OUT) :: Open_Status

        ! Check to see if the file exists
          OPEN(UNIT=Unit_Number,FILE = File_Name,STATUS='old',ACTION='read', &
               IOSTAT = Open_Status)
          IF(Open_Status .GT. 0) THEN
           WRITE(*,*) "**** Cannot Open ", File_Name," ****"
           STOP
           RETURN
          END IF
          END SUBROUTINE Check_File
   !===============================================================================
          FUNCTION File_Length(File_Name,Unit_Number)
          INTEGER :: File_Length
          INTEGER, INTENT(IN) :: Unit_Number
          CHARACTER(LEN=13),INTENT(IN) :: File_Name
          INTEGER :: Open_Status,Input_Status

        ! Calls subroutine to check on status of file
          CALL Check_File(Unit_Number,Open_Status,File_Name)
          IF(Open_Status .GT. 0)THEN
           WRITE(*,*) "**** Cannot Read", File_Name," ****"
           STOP
           RETURN
          END IF

        ! Determine File Size
          File_Length = 0
          DO 300
           READ(Unit_Number,*,IOSTAT = Input_Status)
           IF(Input_Status .LT. 0) EXIT
           File_Length = File_Length + 1
     300  CONTINUE
          CLOSE(Unit_Number)
          END FUNCTION File_Length
   !===============================================================================
          SUBROUTINE Read_File(File_Name,Unit_Number,Column1,Max_Value)
          INTEGER, INTENT(IN) :: Unit_Number
          REAL, DIMENSION(:), ALLOCATABLE,INTENT(OUT) :: Column1
          CHARACTER(LEN=13),INTENT(IN) :: File_Name
          REAL, INTENT(OUT) :: Max_Value
          INTEGER :: Array_Size,n

        ! Determines the array size and allocates the array
          Array_Size = File_Length(File_Name,Unit_Number)
          ALLOCATE (Column1(Array_Size))

        ! - Reads in columnar array and determines the element with
        !   the largest value
           Max_Value = 0.0
           OPEN(UNIT= Unit_Number,File = File_Name)
           DO n = 1,Array_Size
            READ(Unit_Number,*) Column1(n)
            IF(Column1(n) .GT. Max_Value) Max_Value = Column1(n)
           END DO
           CLOSE(Unit_Number)
           END SUBROUTINE Read_File
   !===============================================================================
           END MODULE READ_COLUMNAR_FILE