- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm having trouble using QSORT with character strings. On Compaq Fortran 6.6 (windows) the code below works but is not ideal because I need to know the string length in the comparison routine CharCIOrder. Attempts to apply Len direct to C1 or C2 cause "array bounds exceeded" on the following line (Len(C1)is equal to179523712) and attempts to apply Len_Trim to C1 or C2 cause "access violation" on the line with Len_Trim. Attempts to debug this crashes the developer studio. On Intel Fortran 9.1 (Linux) the code doesn't work. It gives a warning about copying the first argumentof QSORT_CHAR to a temp array and then fails with "memory fault" before leaving QSORT. Adding write statements shows the code enters the routine CharCIOrder but doesn't complete C1L=C1 and C2L=C2.
Note that, in the case I've been running, MaxCharLength (defined in GlobalParametersModule) is 42, and Names is a 7 element array section.
I'm new to passing routine names as arguments, so its quite likely I'm doing something wrong. Can anyone offer any advice?
Many thanks
Here's the code:
Module SortModule
USE DFPort ! Compaq
! USE IFLPORT ! Intel
Implicit None
Private
Public :: SortInPlace
Contains
Subroutine SortInPlace(Names)
Character(*) :: Names(:)
Integer(2), External :: CharCIOrder
Call QSort(Array = Names, Len = Size(Names), iSize = Len(Names(1)), Compar = CharCIOrder)
End Subroutine SortInPlace
End Module SortModule
!-------------------------------------------------------------------------------------------------------------
Function CharCIOrder(C1, C2)
! Case insensitive order comparison.
Use GlobalParametersModule
Implicit None
! Argument list:
Character(*), Intent(In) :: C1 !} Character strings to be compared.
Character(*), Intent(In) :: C2 !}
! Function result:
Integer(2) :: CharCIOrder ! -1 if C1 before C2, 0 if C1 = C2, and 1 if C1 after C2.
! Locals:
Character(MaxCharLength) :: C1L !} Local copies of C1 and C2.
Character(MaxCharLength) :: C2L !}
Integer :: i ! Loop index.
C1L = C1
C2L = C2
Do i = 1, Len_Trim(C1L)
If ('a' <= C1L(i:i) .and. C1L(i:i) <= 'z') C1L(i:i) = Char(IChar(C1L(i:i)) - IChar('a') + IChar('A'))
End Do
Do i = 1, Len_Trim(C2L)
If ('a' <= C2L(i:i) .and. C2L(i:i) <= 'z') C2L(i:i) = Char(IChar(C2L(i:i)) - IChar('a') + IChar('A'))
End Do
If (C1L == C2L) Then
CharCIOrder = 0
Else If (C1L < C2L) Then
CharCIOrder = - 1
Else
CharCIOrder = 1
End If
End Function CharCIOrder
Note that, in the case I've been running, MaxCharLength (defined in GlobalParametersModule) is 42, and Names is a 7 element array section.
I'm new to passing routine names as arguments, so its quite likely I'm doing something wrong. Can anyone offer any advice?
Many thanks
Here's the code:
Module SortModule
USE DFPort ! Compaq
! USE IFLPORT ! Intel
Implicit None
Private
Public :: SortInPlace
Contains
Subroutine SortInPlace(Names)
Character(*) :: Names(:)
Integer(2), External :: CharCIOrder
Call QSort(Array = Names, Len = Size(Names), iSize = Len(Names(1)), Compar = CharCIOrder)
End Subroutine SortInPlace
End Module SortModule
!-------------------------------------------------------------------------------------------------------------
Function CharCIOrder(C1, C2)
! Case insensitive order comparison.
Use GlobalParametersModule
Implicit None
! Argument list:
Character(*), Intent(In) :: C1 !} Character strings to be compared.
Character(*), Intent(In) :: C2 !}
! Function result:
Integer(2) :: CharCIOrder ! -1 if C1 before C2, 0 if C1 = C2, and 1 if C1 after C2.
! Locals:
Character(MaxCharLength) :: C1L !} Local copies of C1 and C2.
Character(MaxCharLength) :: C2L !}
Integer :: i ! Loop index.
C1L = C1
C2L = C2
Do i = 1, Len_Trim(C1L)
If ('a' <= C1L(i:i) .and. C1L(i:i) <= 'z') C1L(i:i) = Char(IChar(C1L(i:i)) - IChar('a') + IChar('A'))
End Do
Do i = 1, Len_Trim(C2L)
If ('a' <= C2L(i:i) .and. C2L(i:i) <= 'z') C2L(i:i) = Char(IChar(C2L(i:i)) - IChar('a') + IChar('A'))
End Do
If (C1L == C2L) Then
CharCIOrder = 0
Else If (C1L < C2L) Then
CharCIOrder = - 1
Else
CharCIOrder = 1
End If
End Function CharCIOrder
Link Copied
8 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sorry - I should have added that "Names" is an array section of character strings each of length MaxCharLength (= 42) and the array section is contiguous. I.e.
Character(MaxCharLength) :: Names(2000)
...
Call SortInPlace(Names(1:7))
Hopefully I haven't got array sections and character substrings muddled up, but I don't think I have!
Character(MaxCharLength) :: Names(2000)
...
Call SortInPlace(Names(1:7))
Hopefully I haven't got array sections and character substrings muddled up, but I don't think I have!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
We have now reproduced the error in a much smaller code, so I can post the entire code and the result here. Hopefully someone might be able to help us. It appears that the character length isn't being passed correctly to the comparison routine, quite probably because we've done something wrong.
Many thanks
Here's the code:
program main
use IFLPort
implicit none
character(10) :: c(7)
Integer(2), External :: OrderCharCI ! Routine used to compute order of character strings.
c(1)='aisjdop'
c(2)='35djf2'
c(3)='ss:ss'
c(4)='MMhQQ'
c(5)='mmHqq'
c(6)='aaaaa'
c(7)='["/'
write(*,*) C
Call QSort(C, Size(C), Len(C(1)), OrderCharCI)
end program main
Function OrderCharCI(C1, C2)
! Computes order of character strings using a case insensitive ordering.
Implicit None
! Argument list:
Character(*), Intent(In) :: C1 !} Character strings to be ordered.
Character(*), Intent(In) :: C2 !}
! Function result:
Integer(2) :: OrderCharCI ! -1 if C1 before C2, 0 if C1 = C2, and 1 if C1 after C2.
! Locals:
Character(10) :: C1L !} Local copies of C1 and C2.
Character(10) :: C2L !}
Integer :: i ! Loop index.
write(*,*)'C1',len(C1)
write(*,*)'C1',C1(1:1)
write(*,*)'C1',C1(1:70)
C1L = C1
C2L = C2
! Note applying Len_Trim direct to C1 or C2 causes fatal error in Compaq Fortran
! - hence use of C1L, C2L. Undesirable because need to hard wire character length (10)
! (or pass by common block?)
! Attempting to debug in this routine causes fatal error in Compaq Fortran
! It doesn't work at all on Intel (Linux) Fortran - it fails with "memory fault" after
! start of routine but before getting to here.
write(*,*) 'about to start do loop'
Do i = 1, Len_Trim(C1L)
If ('a' <= C1L(i:i) .and. C1L(i:i) <= 'z') C1L(i:i) = Char(IChar(C1L(i:i)) - IChar('a') + IChar('A'))
End Do
Do i = 1, Len_Trim(C2L)
If ('a' <= C2L(i:i) .and. C2L(i:i) <= 'z') C2L(i:i) = Char(IChar(C2L(i:i)) - IChar('a') + IChar('A'))
End Do
If (C1L == C2L) Then
OrderCharCI = 0
Else If (C1L < C2L) Then
OrderCharCI = - 1
Else
OrderCharCI = 1
End If
End Function OrderCharCI
and here's the result:
$ ifort -V
Intel Fortran Compiler for 32-bit applications, Version 9.1 Build 20060927
Z Package ID: l_fc_c_9.1.039
Copyright (C) 1985-2006 Intel Corporation. All rights reserved.
$ ifort -C -w -extend_source -nbs -Vaxlib -auto main.f90 -o sorttest.exe
$ sorttest.exe
aisjdop 35djf2 ss:ss MMhQQ mmHqq aaaaa ["/
C1 -1073746048
forrtl: severe (408): fort: (4): Variable C1 has substring ending point 1 which
is greater than the variable length of -1073746048
Image PC Routine Line Source
sorttest.exe 080825D0 Unknown Unknown Unknown
sorttest.exe 0808149D Unknown Unknown Unknown
sorttest.exe 08062066 Unknown Unknown Unknown
sorttest.exe 0804ACE0 Unknown Unknown Unknown
sorttest.exe 080496D0 Unknown Unknown Unknown
libc.so.6 0049AA5A Unknown Unknown Unknown
libc.so.6 0049AA2B Unknown Unknown Unknown
libc.so.6 0049AA0D Unknown Unknown Unknown
libc.so.6 0049ACCC Unknown Unknown Unknown
sorttest.exe 08049CA1 Unknown Unknown Unknown
sorttest.exe 0804940A Unknown Unknown Unknown
libc.so.6 00485DE3 Unknown Unknown Unknown
sorttest.exe 08049341 Unknown Unknown Unknown
$ ifort -w -extend_source -nbs -Vaxlib -auto main.f90 -o sorttest.exe
$ sorttest.exe
aisjdop 35djf2 ss:ss MMhQQ mmHqq aaaaa ["/
C1 -1073746048
C13
C135djf2 ss:ss MMhQQ mmHqq aaaaa ["/ I
Memory fault
$
Many thanks
Here's the code:
program main
use IFLPort
implicit none
character(10) :: c(7)
Integer(2), External :: OrderCharCI ! Routine used to compute order of character strings.
c(1)='aisjdop'
c(2)='35djf2'
c(3)='ss:ss'
c(4)='MMhQQ'
c(5)='mmHqq'
c(6)='aaaaa'
c(7)='["/'
write(*,*) C
Call QSort(C, Size(C), Len(C(1)), OrderCharCI)
end program main
Function OrderCharCI(C1, C2)
! Computes order of character strings using a case insensitive ordering.
Implicit None
! Argument list:
Character(*), Intent(In) :: C1 !} Character strings to be ordered.
Character(*), Intent(In) :: C2 !}
! Function result:
Integer(2) :: OrderCharCI ! -1 if C1 before C2, 0 if C1 = C2, and 1 if C1 after C2.
! Locals:
Character(10) :: C1L !} Local copies of C1 and C2.
Character(10) :: C2L !}
Integer :: i ! Loop index.
write(*,*)'C1',len(C1)
write(*,*)'C1',C1(1:1)
write(*,*)'C1',C1(1:70)
C1L = C1
C2L = C2
! Note applying Len_Trim direct to C1 or C2 causes fatal error in Compaq Fortran
! - hence use of C1L, C2L. Undesirable because need to hard wire character length (10)
! (or pass by common block?)
! Attempting to debug in this routine causes fatal error in Compaq Fortran
! It doesn't work at all on Intel (Linux) Fortran - it fails with "memory fault" after
! start of routine but before getting to here.
write(*,*) 'about to start do loop'
Do i = 1, Len_Trim(C1L)
If ('a' <= C1L(i:i) .and. C1L(i:i) <= 'z') C1L(i:i) = Char(IChar(C1L(i:i)) - IChar('a') + IChar('A'))
End Do
Do i = 1, Len_Trim(C2L)
If ('a' <= C2L(i:i) .and. C2L(i:i) <= 'z') C2L(i:i) = Char(IChar(C2L(i:i)) - IChar('a') + IChar('A'))
End Do
If (C1L == C2L) Then
OrderCharCI = 0
Else If (C1L < C2L) Then
OrderCharCI = - 1
Else
OrderCharCI = 1
End If
End Function OrderCharCI
and here's the result:
$ ifort -V
Intel Fortran Compiler for 32-bit applications, Version 9.1 Build 20060927
Z Package ID: l_fc_c_9.1.039
Copyright (C) 1985-2006 Intel Corporation. All rights reserved.
$ ifort -C -w -extend_source -nbs -Vaxlib -auto main.f90 -o sorttest.exe
$ sorttest.exe
aisjdop 35djf2 ss:ss MMhQQ mmHqq aaaaa ["/
C1 -1073746048
forrtl: severe (408): fort: (4): Variable C1 has substring ending point 1 which
is greater than the variable length of -1073746048
Image PC Routine Line Source
sorttest.exe 080825D0 Unknown Unknown Unknown
sorttest.exe 0808149D Unknown Unknown Unknown
sorttest.exe 08062066 Unknown Unknown Unknown
sorttest.exe 0804ACE0 Unknown Unknown Unknown
sorttest.exe 080496D0 Unknown Unknown Unknown
libc.so.6 0049AA5A Unknown Unknown Unknown
libc.so.6 0049AA2B Unknown Unknown Unknown
libc.so.6 0049AA0D Unknown Unknown Unknown
libc.so.6 0049ACCC Unknown Unknown Unknown
sorttest.exe 08049CA1 Unknown Unknown Unknown
sorttest.exe 0804940A Unknown Unknown Unknown
libc.so.6 00485DE3 Unknown Unknown Unknown
sorttest.exe 08049341 Unknown Unknown Unknown
$ ifort -w -extend_source -nbs -Vaxlib -auto main.f90 -o sorttest.exe
$ sorttest.exe
aisjdop 35djf2 ss:ss MMhQQ mmHqq aaaaa ["/
C1 -1073746048
C13
C135djf2 ss:ss MMhQQ mmHqq aaaaa ["/ I
Memory fault
$
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
nii.f90(20): error #6285: There is no matching specific subroutine for this generic subroutine call. [QSORT]
Call QSort(C, Size(C), Len(C(1)), OrderCharCI
i.e. there is no implementation of qsort provided for arrays of CHARACTER (at least not in my copy of ifport.f90)
Call QSort(C, Size(C), Len(C(1)), OrderCharCI
i.e. there is no implementation of qsort provided for arrays of CHARACTER (at least not in my copy of ifport.f90)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I do not know theinternals of how QSorthandles the character arguments and their associated lengths and I'm unable to find a working solution. I'll inquire with the library developer about this and post again when I know more.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Tim - the QSORT_CHAR interface is defined in ifport.f90 as far back as 8.1. Double check the declared types for the arguments or perhaps you compiled with -i8 (or similar)?
Nameiii - Our Fortran RTL developers analyzed the case and found the issue relates to our QSORT implementation calling the ANSI system qsort (libc) which does not account for the character lengths for arguments C1 & C2 as you determined. They are continuing to investigate a resolution.
As a work around, you could try using your defined parameter, MaxCharLength, inside OrderCharCI to declare C1 and C2 with CHARACTER(MaxCharLength) instead of CHARACTER(*). This will not work with the -C (at least not the -check bounds aspect), so you must avoid using at least bounds checking with this work around.
I will update when I learn more.
(Internal tracking id: DPD200139597)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Many thanks. Following your suggestion, declaring C1 & C2 as Character(10) (in the short example code) works. An alternative is to replace C1L = C1 etc by C1L = C1(1:10). Its slightly surprising that this works as C1L has length 10 and so I would not have expected the program to look beyond 1:10, even without this being specified. As you indicated, neither method works with the -C compilation option.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm now passing the character lengths to the comparison subroutine via a public module variable, so this information now bypasses QSort. The arguments C1 and C2 to the comparison routine are then declared with this length. This seems to work and is a satisfactory solution for us. It also no longer seems necessary to turn off bounds checking. Probably I was wrong in thinking bounds checking needed suppressing or it might have needed suppressing only because of the write(*,*) C1(1:70) which was deliberately looking outside the bounds to see what was happening.
Thanks again for your help.
Thanks again for your help.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Appreciate the updates on the additional alternatives. Those could prove useful for others too. I'm glad you found satisfactory solution.

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page