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

Program reports an error that apparently doesn't exist

当运行使用命令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行下标的none为零,所以我不明白为什么会出现这个错误。 我在第 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

添加一些打印语句,当您处于内部循环时,您将看到它如何与 t(0)=-1 一起使用。下一步是用 j=0 测试 ((j>-1).and.(ichar(x((i+1):(i+1)))/=ichar(x((j+1):(j+1))))),这会生成你现在不理解的内容。

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

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

也就是说,假设 j 是正数。然后第 9 行通过 .TRUE. 并检查从第 10 行开始的循环的条件。 while 条件表达式的左侧是 .TRUE.,我们假设右侧也是。使循环迭代。

在某些时候,也许 j(t) 会变成负数。然后我们回到第 10 行并检查 while 条件。那时,我们看到 x 的越界错误:回想一下,if 语句没有被命中,并且带有 .AND. 的表达式没有短路。 [也就是说,左侧 j>-1 不能确保右侧 j 非负求值。]