Fortran Coder

标题: 动态数组内存问题 [打印本页]

作者: wxy    时间: 2017-9-15 17:51
标题: 动态数组内存问题
运行到24行时出现内存错误提示,不明白什么原因
[Fortran] 纯文本查看 复制代码
Program weather
  Implicit None

  Integer l, i, j, m, daysinyear, k, mm, e, z
  Integer, Allocatable :: site1(:), site2(:), year(:), month(:), day(:)

  Real, Allocatable :: lat(:), lon(:), h(:), tmax(:), tmin(:), lonx(:), laty(:)
  Integer :: ave, ier
  Real :: h2

  Character (45) :: filename = 'SURF_CLI_CHN_MUL_DAY-TEM-12001-123456.txt'
  Character (8) :: outfile = '12345678'
  Character (Len=20) :: line

!=====================================
  Open (5, File='D:\气象数据New\经纬度高程\经纬度高程.txt')
  e = 2421
  Allocate (site2(e), lonx(e), laty(e))
  Do z = 1, e
    Read (5, *) site2(z), lonx(z), laty(z), h2
    write(*,*) site2(z), lonx(z), laty(z), h2
  End Do
  Deallocate (site2, lonx, laty)
  Close (5)
  Do l = 2010, 2015
    Do j = 1, 12
      Write (filename(32:37), '(i6)') l*100 + j
      Open (Unit=11, File='D:\气象数据\气温\'//filename, Action='READ')

      m = 0
      Do
        Read (11, *, Iostat=ier) line
        If (ier==-1) Exit ! end-of-file
        m = m + 1
      End Do
      Allocate (site1(m), lat(m), lon(m), h(m), year(m), month(m), day(m), tmax(m), tmin(m))

      Rewind (11)
      mm = 0
      Do i = 1, m
        mm = mm + 1
        Read (11, *) site1(mm), lat(mm), lon(mm), h(mm), year(mm), month(mm), day(mm), ave, tmax(mm), tmin(mm)
        lat(mm) = lat(mm)/100
        lon(mm) = lon(mm)/100

        tmax(mm) = tmax(mm)*0.1
        tmin(mm) = tmin(mm)*0.1
        If (h(mm)>=100000) Then
          h(mm) = (h(mm)-100000)
        End If
        h(mm) = h(mm)*0.1
        If (tmax(mm)==3270.0 .Or. tmax(mm)==3276.6 .Or. tmin(mm)==3270.0 .Or. tmin(mm)==3276.6) mm = mm - 1

      End Do
      Close (Unit=11)

      Do k = 1, daysinyear(l, j)
        Write (outfile(1:8), '(i8)') l*10000 + j*100 + k
        Open (Unit=15, File='D:\气象数据\tmax\'//outfile//'.txt')
        Open (Unit=16, File='D:\气象数据\tmin\'//outfile//'.txt')
        Do i = 1, mm

          If (l==year(i) .And. j==month(i) .And. k==day(i)) Then


            Do While (site1(i)==site2(z))
              Write (15, '(i5,2x,f6.2,2x,f5.2,2x,f12.4,2x,f12.4,2x,f6.2)') &
              &site1(i), lon(i), lat(i), lonx(z), laty(z), tmax(i) + (h(i)/100)*0.6
! "(i5,2x,f5.2,2x,f6.2,2x,f5.0,2x,i5,2x,i2,2x,i2,2x,f6.2)"
              Write (16, '(i5,2x,f6.2,2x,f5.2,2x,f12.4,2x,f12.4,2x,f6.2)') &
              &site1(i), lon(i), lat(i), lonx(z), laty(z), tmin(i) + (h(i)/100)*0.6
              Print *, site1(i), year(i), month(i), day(i)

            End Do

          End If
        End Do
        Close (Unit=15)
      End Do

      Deallocate (site1, lat, lon, h, year, month, day, tmax, tmin)
    End Do
  End Do

End Program weather

!=======================================

Integer Function daysinyear(year, month)
  Integer, Intent (In) :: year, month

  Integer :: daysinmonth(12) = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]

  If (((mod(year,4)==0) .And. (mod(year,100)/=0)) .Or. (mod(year,400)==0)) Then
    daysinmonth(2) = 29
  Else
    daysinmonth(2) = 28
  End If

  daysinyear = daysinmonth(month)
End Function daysinyear

QQ截图20170915175358.png (39.82 KB, 下载次数: 506)

QQ截图20170915175358.png

作者: chiangtp    时间: 2017-9-15 21:31
line24: CLOSE(UNIT=5)?
不要用 UNIT= 0, 5, 6 對應到 diskfile (尤其是又有 READ/WRITE(*,...)時, compiler會暈車)

請試試看, 是不是這個問題
作者: wxy    时间: 2017-9-16 00:15
本帖最后由 wxy 于 2017-9-16 00:29 编辑
chiangtp 发表于 2017-9-15 21:31
line24: CLOSE(UNIT=5)?
不要用 UNIT= 0, 5, 6 對應到 diskfile (尤其是又有 READ/WRITE(*,...)時, compile ...

额 我换成其他10,13等还是同样错误,我在运行时,到第24行运行都没问题,是16-24行这部分循环运行结束时报错,我想是不是后面67行这儿使用之前read内容时出错了
作者: chiangtp    时间: 2017-9-16 00:31
wxy 发表于 2017-9-16 00:15
额 我换成其他10,13等还是同样错误

仍是 "运行到24行, CLOSE(UNIT=13), 出现内存错误提示"?
i.e., 還沒執行到 "Do l = 2010, 2015", 就runtime error?

請把 "program weather"+"经纬度高程.txt" 把包, 讓我download實際測試, 謝謝
作者: chiangtp    时间: 2017-9-16 00:44
wxy 发表于 2017-9-16 00:15
额 我换成其他10,13等还是同样错误,我在运行时,到第24行运行都没问题,是16-24行这部分循环运行结束时报 ...

抱歉,
delete line 23: Deallocate (site2, lonx, laty)
END PROGRAM之前, 方可Deallocate (site2, lonx, laty),

后面 lines66-71这儿使用之前read内容:  site2(z), lonx(z), laty(z)
subscript "z" 是不對的???
作者: chiangtp    时间: 2017-9-16 01:05
chiangtp 发表于 2017-9-16 00:44
抱歉,
delete line 23: Deallocate (site2, lonx, laty)
END PROGRAM之前, 方可Deallocate (site2, lonx, ...

[Fortran] 纯文本查看 复制代码
      REWIND(UNIT=11)
      mm = 0
      DO i = 1, m
        mm = mm + 1
        READ(11,*) site1(mm), lat(mm), lon(mm), h(mm), year(mm), month(mm), day(mm), ave, tmax(mm), tmin(mm)
        IF( tmax(mm)==3270.0 .OR. tmax(mm)==3276.6 .OR. tmin(mm)==3270.0 .OR. tmin(mm)==3276.6 ) THEN
          mm = mm - 1
          CYCLE
        END IF

        IF( h(mm) >= 100000.0 ) h(mm) = h(mm) - 100000.0
        h   (mm) = h   (mm)*0.1
        tmax(mm) = tmax(mm)*0.1
        tmin(mm) = tmin(mm)*0.1
        lon (mm) = lon (mm)/100.0
        lat (mm) = lat (mm)/100.0
      END DO
      CLOSE(UNIT=11)

      DO k = 1, daysinyear(l,j)
        WRITE(outfile(1:8),'(i8)') l*10000 + j*100 + k
        OPEN( UNIT=15, FILE='...' )
        OPEN( UNIT=16, FILE='...' )

        100 FORMAT(i5,2x,f6.2,2x,f5.2,2x,f12.4,2x,f12.4,2x,f6.2)
        DO i = 1, mm
          IF( l/=year(i) .OR. j/=month(i) .OR. k==day(i) ) CYCLE
          DO z = 1, e
            IF( site1(i) == site2(z) ) THEN
              WRITE(15,100) site1(i), lon(i), lat(i), lonx(z), laty(z), tmax(i)+(h(i)/100)*0.6
              WRITE(16,100) site1(i), lon(i), lat(i), lonx(z), laty(z), tmin(i)+(h(i)/100)*0.6
              WRITE(*,*) site1(i), year(i), month(i), day(i)
            END IF
          END DO
        END DO

        CLOSE(UNIT=15)
      END DO

作者: chiangtp    时间: 2017-9-16 01:09
chiangtp 发表于 2017-9-16 01:05
[Fortran] 纯文本查看 复制代码
      REWIND(UNIT=11)
      mm = 0
      DO i = 1, m

[mw_shl_code=fortran,true]
  CLOSE(UNIT=15)
  CLOSE(UNIT=16)
END DO

作者: chiangtp    时间: 2017-9-16 01:18
chiangtp 发表于 2017-9-16 01:09

[Fortran] 纯文本查看 复制代码
  e = 2421
  ALLOCATE( site2(e), lonx(e), laty(e) )

  OPEN( UNIT=15, FILE='...' )
  DO z = 1, e
    READ(15,*) site2(z), lonx(z), laty(z), h2
    WRITE(*,*) site2(z), lonx(z), laty(z), h2
  END DO
  CLOSE( UNIT=15 )

  !-----------------

  Do l = 2010, 2015
  Do j = 1, 12
    WRITE(filename(32:37), '(i6)') l*100 + j
    OPEN( UNIT=11, FILE='...', ACTION='READ' )
    m = 0
    DO
      READ(11,*,IOSTAT=ier) line
      IF( ier == -1 ) EXIT ! end-of-file
      m = m + 1
    END DO
    ALLOCATE( site1(m), lat(m), lon(m), h(m), year(m), month(m), day(m), tmax(m), tmin(m) )

    REWIND( UNIT=11 )
    mm = 0
    DO i = 1, m
      mm = mm + 1
      READ(11,*) site1(mm), lat(mm), lon(mm), h(mm), year(mm), month(mm), day(mm), ave, tmax(mm), tmin(mm)
      IF( tmax(mm)==3270.0 .OR. tmax(mm)==3276.6 .OR. tmin(mm)==3270.0 .OR. tmin(mm)==3276.6 ) THEN
        mm = mm - 1
        CYCLE
      END IF

      IF( h(mm) >= 100000.0 ) h(mm) = h(mm) - 100000.0
      h   (mm) = h   (mm)*0.1
      tmax(mm) = tmax(mm)*0.1
      tmin(mm) = tmin(mm)*0.1
      lon (mm) = lon (mm)/100.0
      lat (mm) = lat (mm)/100.0
    END DO
    CLOSE( UNIT=11 )

    !-----

    DO k = 1, daysinyear(l,j)
      WRITE(outfile(1:8),'(i8)') l*10000 + j*100 + k
      OPEN( UNIT=15, FILE='...' )
      OPEN( UNIT=16, FILE='...' )

      100 FORMAT(i5,2x,f6.2,2x,f5.2,2x,f12.4,2x,f12.4,2x,f6.2)
      DO i = 1, mm
        IF( l/=year(i) .OR. j/=month(i) .OR. k==day(i) ) CYCLE
        DO z = 1, e
          IF( site1(i) == site2(z) ) THEN
            WRITE(15,100) site1(i), lon(i), lat(i), lonx(z), laty(z), tmax(i)+(h(i)/100)*0.6
            WRITE(16,100) site1(i), lon(i), lat(i), lonx(z), laty(z), tmin(i)+(h(i)/100)*0.6
            WRITE(*,*) site1(i), year(i), month(i), day(i)
          END IF
        END DO
      END DO
      CLOSE( UNIT=15 )
      CLOSE( UNIT=16 )
    END DO

    DEALLOCATE( site1, lat, lon, h, year, month, day, tmax, tmin )
  END DO
  END DO

  DEALLOCATE( site2, lonx, laty )

END PROGRAM weather

作者: chiangtp    时间: 2017-9-16 11:38
chiangtp 发表于 2017-9-16 01:18
[Fortran] 纯文本查看 复制代码
  e = 2421
  ALLOCATE( site2(e), lonx(e), laty(e) )

1. 還是有點小錯:  "k==day(i)"  ---> "k/=day(i)"
2. 改善Loop的效率: "IF(l/=year(i) .OR. j/=month(i))"往前提 (not function of "iday" loop)
3. 重要的subscripts: "l, j, k" ---> "iyear, imonth, iday", 可讀性高
4. 數理/Fortran的文化: "z"不宜為subscript "iz"可也
5. for REAL: "100" ---> "100.0"
[mw_shl_code=fortran,true]  INTEGER :: iyear, imonth, iday, nn

  !-----------------

  nn = 2421
  ALLOCATE( site2(nn), lonx(nn), laty(nn) )

  OPEN( UNIT=11, FILE='...' )
  DO i = 1, nn
    READ(11,*) site2(i), lonx(i), laty(i)
  END DO
  CLOSE( UNIT=11 )

  !-----------------

  DO iyear  = 2010, 2015
  DO imonth = 1, 12
    WRITE(filename(32:37), '(i6)') iyear*100 + imonth
    OPEN( UNIT=11, FILE='...', ACTION='READ' )
    m = 0
    DO
      READ(11,*,IOSTAT=ier) line
      IF( ier == -1 ) EXIT ! end-of-file
      m = m + 1
    END DO
    ALLOCATE( site1(m), lat(m), lon(m), h(m), year(m), month(m), day(m), tmax(m), tmin(m) )

    REWIND( UNIT=11 )
    mm = 0
    DO i = 1, m
      mm = mm + 1
      READ(11,*) site1(mm), lat(mm), lon(mm), h(mm), year(mm), month(mm), day(mm), ave, tmax(mm), tmin(mm)
      IF( year(mm)/=iyear .OR. month(mm)/=imonth .OR. &
          tmax(mm)==3270.0 .OR. tmax(mm)==3276.6 .OR. tmin(mm)==3270.0 .OR. tmin(mm)==3276.6 ) THEN
        mm = mm - 1
        CYCLE
      END IF

      IF( h(mm) >= 100000.0 ) h(mm) = h(mm) - 100000.0
      h   (mm) = h   (mm)*0.1
      tmax(mm) = tmax(mm)*0.1
      tmin(mm) = tmin(mm)*0.1
      lon (mm) = lon (mm)/100.0
      lat (mm) = lat (mm)/100.0
    END DO
    CLOSE( UNIT=11 )

    !-----
    IF( mm == 0 ) CYCLE
    !-----

    DO iday = 1, daysinyear(iyear,imonth)
      WRITE(outfile(1:8),'(i8)') iyear*10000 + imonth*100 + iday
      OPEN( UNIT=15, FILE='...' )
      OPEN( UNIT=16, FILE='...' )

      100 FORMAT(i5,2x,f6.2,2x,f5.2,2x,f12.4,2x,f12.4,2x,f6.2)
      DO i = 1, mm
        IF( iday /= day(i) ) CYCLE
        DO j = 1, nn
          IF( site1(i) /= site2(j) ) CYCLE
          WRITE(15,100) site1(i), lon(i), lat(i), lonx(j), laty(j), tmax(i)+(h(i)/100.0)*0.6
          WRITE(16,100) site1(i), lon(i), lat(i), lonx(j), laty(j), tmin(i)+(h(i)/100.0)*0.6
          WRITE(*,*) site1(i), year(i), month(i), day(i)
        END DO
      END DO
      CLOSE( UNIT=15 )
      CLOSE( UNIT=16 )
    END DO

    DEALLOCATE( site1, lat, lon, h, year, month, day, tmax, tmin )
  END DO
  END DO

  DEALLOCATE( site2, lonx, laty )

END PROGRAM weather
作者: wxy    时间: 2017-9-16 13:11
本帖最后由 wxy 于 2017-9-16 13:21 编辑
chiangtp 发表于 2017-9-16 11:38
1. 還是有點小錯:  "k==day(i)"  ---> "k/=day(i)"
2. 改善Loop的效率: "IF(l/=year(i) .OR. j/=month(i) ...

不好意思刚看到 非常感谢 ,我还是不太明白这个报错是什么意思,为甚末之前将deallocate放在下一个do循环之前就会报错,放在end program 之前就没事,deallocate不是将之前的动态数组内存释放掉吗,2. '/=,.or.'和‘==,.and.’这里有点转不过来,'/='不是‘不等于‘’吗
作者: chiangtp    时间: 2017-9-16 13:57
wxy 发表于 2017-9-16 13:11
不好意思刚看到 非常感谢 ,我还是不太明白这个报错是什么意思,为甚末之前将deallocate放在下一个do循环 ...

(1) 为甚末之前将deallocate放在下一个do循环之前就会报错,放在end program 之前就没事
DEALLOCATE(site2, lonx, laty)之後, 尚未再次ALLOCATE(site2(...), lonx(...), laty(...))之前, 不得access "site2, lonx, laty"等arrays

(2) '/=,.or.'和‘==,.and.’这里有点转不过来
[Fortran] 纯文本查看 复制代码
DO i = 1, m
  IF( a /= b ) CYCLE
  ... ! do something for (a==b)
END DO

or,

DO i = 1, m
  IF( a == b ) THEN
    ... ! do something for (a==b)
  END IF
END DO


(3) 可嘗試:
[Fortran] 纯文本查看 复制代码
    REWIND( UNIT=11 )
    mm = 0
    DO i = 1, m
      mm = mm + 1
      READ(11,*) site1(mm), lat(mm), lon(mm), h(mm), year(mm), month(mm), day(mm), ave, tmax(mm), tmin(mm)
      IF( year(mm)/=iyear .OR. month(mm)/=imonth .OR. &
          tmax(mm)==3270.0 .OR. tmax(mm)==3276.6 .OR. tmin(mm)==3270.0 .OR. tmin(mm)==3276.6 ) mm = mm - 1
    END DO
    CLOSE( UNIT=11 )

    WHERE( h(1:mm) >= 100000.0 ) h(1:mm) = h(1:mm) - 100000.0
    h   (1:mm) = h   (1:mm)*0.1
    tmax(1:mm) = tmax(1:mm)*0.1
    tmin(1:mm) = tmin(1:mm)*0.1
    lon (1:mm) = lon (1:mm)/100.0
    lat (1:mm) = lat (1:mm)/100.0

作者: wxy    时间: 2017-9-16 16:44
chiangtp 发表于 2017-9-16 13:57
(1) 为甚末之前将deallocate放在下一个do循环之前就会报错,放在end program 之前就没事
DEALLOCATE(site ...

嗯嗯 明白了 非常感谢




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