程序报告显然不存在的错误

时间:2017-07-18 18:37:19

标签: fortran gfortran fortran95

使用命令gfortran -g -fcheck=all -Wall -Wextra myprogram.f95编译程序后运行程序时出现以下错误

Fortran runtime error: Substring out of bounds: lower bound (0) of 'x' is less than one

据报道,错误位于以下子程序的第10行。

 01 subroutine create_table_MP (x, m, t)
 02   implicit none
 03   character(len=*), intent(in) :: x
 04   integer, dimension(0:), intent(inout) :: t
 05   integer, intent(in) :: m
 06   integer :: i, j
 07   i=0; t(0)=-1; j=-1
 08   do while (i < m)
 09       if (j > -1) then
 10           do while ((j>-1).and.(ichar(x((i+1):(i+1)))/=ichar(x((j+1):(j+1)))))
 11               j = t(j)
 12           end do
 13       end if
 14       i=i+1; j=j+1; t(i)=j
 15   end do
 16 end subroutine create_table_MP

但是if(j > -1)命令保证第10行的下标都不为零,所以我不明白为什么会出现这个错误。 我在第10行之前放了一个print *, j+1,正如预期的那样,j + 1从不假定零值。 我不知道错误在哪里。有人可以帮助我吗?

使用该子程序的整个程序的代码是

module search
    implicit none

contains
    subroutine MP (x, y, m, n)
        implicit none
        character(len=*), intent(in) :: x, y
        integer, intent(in) :: m, n
        integer, dimension(0:m-1) :: table
        integer :: i, j

        call create_table_MP(x, m, table)

        i=0; j=0

        do while (j<n)
            do while ((i>-1).and.(ichar(x((i+1):(i+1)))/=ichar(y((j+1):(j+1)))))
                i = table(i)
            end do

            i=i+1; j=j+1

            ! if (i >= m) then
            !     print *, j-i
            !     i = table(i)
            ! end if
        end do
    end subroutine MP

    subroutine KMP (x, y, m, n)
        implicit none
        character(len=*), intent(in) :: x, y
        integer, intent(in) :: m, n
        integer, dimension(0:m-1) :: table
        integer :: i, j

        call create_table_KMP(x, m, table)

        i=0; j=0

        do while(j<n)
            do while((i>-1).and.(ichar(x((i+1):(i+1)))/=ichar(y((j+1):(j+1)))))
                i = table(i)
            end do

            i=i+1; j=j+1

            ! if (i >= m) then
            !     print *, j-i
            !     i = table(i)
            ! end if

        end do
    end subroutine KMP

    subroutine create_table_MP (x, m, t)
        implicit none
        character(len=*), intent(in) :: x
        integer, dimension(0:), intent(inout) :: t
        integer, intent(in) :: m
        integer :: i, j

        i=0; t(0)=-1; j=-1

        do while (i < m)
            if (j > -1) then
                do while ((j>-1).and.(ichar(x((i+1):(i+1)))/=ichar(x((j+1):(j+1)))))
                    j = t(j)
                end do
            end if

            i=i+1; j=j+1; t(i)=j
        end do
    end subroutine create_table_MP

    subroutine create_table_KMP (x, m, t)
        implicit none
        character(len=*), intent(in) :: x
        integer, dimension(0:), intent(inout) :: t
        integer, intent(in) :: m
        integer :: i, j

        i=0; t(0)=-1; j=-1

        do while (i < m)
            if (j > -1) then
                do while ((j>-1).and.(ichar(x((i+1):(i+1)))/=ichar(x((j+1):(j+1)))))
                    j = t(j)
                end do
            end if

            i=i+1; j=j+1

            if ((i<m).and.(ichar(x((i+1):(i+1)))==ichar(x((j+1):(j+1))))) then
                t(i) = t(j)
            else
                t(i) = j
            end if

        end do
    end subroutine create_table_KMP
end module search

program test
    use search
    implicit none
    character(len=*), parameter :: string1 = 'gga', file1 = 'file.txt'

    call search_1(string1, file1)

contains
    subroutine search_1 (string,name_file)
        implicit none
        character(len=*), intent(in) :: string, name_file
        character(len=200) :: message
        integer :: l_character
        logical :: exist1 = .false., iend = .true.

        inquire(FILE=name_file, EXIST=exist1)
        if(.not.(exist1)) then
            print *,'The file ',name_file,' doesnt exist.'
            print *,'Press ENTER to finish the program.'
            read (*,*)
            stop
        end if

        open(UNIT=10, FILE=name_file, STATUS='OLD')
        do
            read(UNIT=10, FMT='(A)', END=1000) message; iend=.false.
            1000 if(iend) then
                    exit
                end if

            call remove(message,l_character)

            iend = .true.
            if (l_character < 1) cycle

            call MP(string, message(1:l_character),len_trim(string), len_trim(message(1:l_character)))
            call KMP(string, message(1:l_character),len_trim(string),len_trim(message(1:l_character)))

        end do

        close(UNIT=10)
    end subroutine search_1

    subroutine remove (message, j)
        implicit none
        character(len=*), intent(inout) :: message
        integer, intent(inout) :: j
        integer :: i

        i=1; j=1
        do
            if (i>len_trim(message)) exit
            ! ichar(a) = 97 and ichar(t) = 116
            if ((ichar(message(i:i))>=97).and.(ichar(message(i:i))<=116)) then
                message(j:j) = message(i:i)
                j = j + 1
            end if
            i = i + 1
        end do

        j = j - 1

    end subroutine remove
end program test

2 个答案:

答案 0 :(得分:4)

第9行的if语句中的条件仅保证j仅对于从第10行开始的循环的第一次迭代不是否定的。在第11行,在该循环内,我们可以看到{{ 1}}取j给出的值。 if语句不会检查是否为负数。

即,假设t(j)为正。然后第9行以j传递,从第10行开始的循环检查其条件。 while条件表达式的左侧是.TRUE.,让我们假设右侧也是。这样循环就会迭代。

在某些时候,也许.TRUE.会变为负面。然后我们回到第10行并检查while条件。此时,我们看到x的出界错误:回想一下if语句没有被命中,而j(t)的表达式没有被短路。 [也就是说,左侧.AND.无法确保右侧评估为j>-1非负面。]

答案 1 :(得分:3)

添加一些打印语句,当您处于内循环中时,您将看到它与t(0)=-1的关系。接下来就是用((j>-1).and.(ichar(x((i+1):(i+1)))/=ichar(x((j+1):(j+1)))))测试j=0,这会产生你现在不理解的东西。

program myprogram
    integer, parameter :: M = 11
    character(M-1) :: x = "0123456789"
    integer, dimension(M) :: t

    call create_table_MP (x, m, t)
contains
    subroutine create_table_MP (x, m, t)
    implicit none
    character(len=*), intent(in) :: x
    integer, dimension(0:), intent(inout) :: t
    integer, intent(in) :: m
    integer :: i, j
    i=0; t(0)=-1; j=-1
    do while (i < m)
        if (j > -1) then
            write(*,*), "outer j = ", j
            do while ((j>-1).and.(ichar(x((i+1):(i+1)))/=ichar(x((j+1):(j+1)))))
                j = t(j)
                write(*,*), "  innerj = ", j
            end do
        end if
        i=i+1; j=j+1; t(i)=j
    end do
    end subroutine create_table_MP
end program myprogram