user7332571
user7332571

Reputation:

Program reports an error that apparently doesn't exist

When running the program after compiling it using the commands gfortran -g -fcheck=all -Wall -Wextra myprogram.f95 the following error appears

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

It is also reported that the error lies on line 10 of the following subroutine.

 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

But the if(j > -1) command guarantees that none of the subscripts of the line 10 is zero, so I don't understand why this error occurred. I put a print *, j+1 before line 10 and, as expected, j+1 never assumes zero value. I don't know where the error is. Could someone please help me?

The code of the entire program in which this subroutine was used is

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

Upvotes: 1

Views: 191

Answers (2)

francescalus
francescalus

Reputation: 32366

The condition in the if statement at line 9 guarantees only that j is not negative only for the first iteration of the loop commencing at line 10. At line 11, inside that loop, we can see that j takes a value given by t(j). Whether this is negative is not checked by that if statement.

That is, assume j is positive. Then line 9 passes with a .TRUE. and the loop commencing at line 10 has its condition checked. The left-hand side of the while condition expression is .TRUE. and let's assume the right-hand side is also. So that the loop iterates.

At some point, perhaps j(t) becomes negative. Then we get back to line 10 and a check of the while condition. At that point, we see the out of bound error for x: recall that the if statement hasn't been hit and the expression with .AND. isn't short-circuited. [That is, the left-hand side j>-1 doesn't ensure that the right-hand side is evaluated with j non-negative.]

Upvotes: 3

innoSPG
innoSPG

Reputation: 4656

Add some print statements and you will see how it goes with t(0)=-1, when you are in the inner loop. The next thing is to test ((j>-1).and.(ichar(x((i+1):(i+1)))/=ichar(x((j+1):(j+1))))) with j=0 which generates what you do not understand for now.

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

Upvotes: 2

Related Questions