Reputation:
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
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
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