From: Richard Maine on
fj <francois.jacq(a)irsn.fr> wrote:

> On 5 juin, 15:09, fj <francois.j...(a)irsn.fr> wrote:
> > On 5 juin, 10:48, Jovan Cormac <limu...(a)gmx.net> wrote:
> >
> > > I have a subroutine that accepts an array of variable-length strings of
> > > variable size (assumed-shape array) and is to output all of those strings:

Here is the core of the problem. There is no such thing as "an array of
variable-length strings". If you have an array, the length attribute
applies equally to the every string in the array. This applies
regardless of whether the length is assumed, deferred, or whatever.
Fiddling with the declaration isn't going to change it.

The "usual" workaround for things where you want different properties
for different elements of an array applies. Make it an array or derived
type, something like

type string_type
character, allocatable :: string*(:)
end string_type
type(string_type) :: strings(2) !-- Or whatever shape.

Then each element of the array can be separately allocated to a
different length. (This requires f2003 for allocatable length).

I'm not at all sure that it would be suitable for the OP's purpose,
though, as, among other things, I don't think you can write a handy
literal form for this.

> > > CALL routine1( (/ 'Hello', ' ', 'World!' /) )
> >
> > This instruction is not legal : all the strings must have the same
> > length ! Your compiler has accepted it (extension) in padding the
> > shortest strings with spaces.
>
> Correction : not legal in FORTRAN-95

Re-correction: not legal in any version of Fortran to date. I haven't
checked f2008, but I doubt it changes this. F2003 has an extension to
string array syntax, but this isn't it. See the example that James Van
Buskirk posted for that form.

The OP's explanation in a separate post that "the standard doesn't
concern me much, since my code compiles with the compiler we use
(Intel)" seems a bit short-sighted in several regards. One of those
regards is that just because the code compiles doesn't mean it does what
he expects. I rather doubt that it does.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
From: dpb on
Jovan Cormac wrote:
> dpb wrote:
>
>> If the question is how to write legal (consistent w/ F95 Standard) array
>> constructor for CHARACTER data, sure...pad all strings in the
>> constructor to the same length.
>>
>> Otherwise, do you mean to ask something different?
....
> Well, truth be told the standard doesn't concern me much, since my code
> compiles with the compiler we use (Intel).

Which is, of course, fine as long as you don't switch compilers or need
the source to be used elsewhere (but, I'm sure you know that)... :)

> What I meant is, is there a way to achieve what I originally described:
> Passing several strings (variable number) of variable length and then
> outputting them all WITHOUT them being either truncated (TRIM) or blown
> up (padded), i.e.: Is there a way to emulate the behavior of WRITE in a
> user-written function? After all,
>
> WRITE(*,*) 'Hello', ' ', 'world'
>
> will do just what I described (without any additional processing, of
> course), so technically, it is certainly possible.

Well, of course, those aren't variable-length strings in the example,
they're three separate constant-length strings. And, of course, native
i/o to the library is different than are user subroutines.

In response to the question, the answer is "yes", but...

You have to understand what you're asking. Fortran (at least to F95,
I'm not positive about the additions w/ F2003 and F2008; there are some
things about allocation on assignment and so on that are related to
dynamically allocated storage, etc., but whether anything to handle a
dynamic-length string array or not, I don't know).

The assumed-length character argument CHARACTER*(*) _DOES_ take on the
length of the argument passed in the subroutine so, technically, it does
what you asked for. That is,

subroutine doit(string)
character*(*) string

write(*,*) len(string)
end

would give 5,1,5 as the output if called as

program showit
call doit('Hello')
call doit(' ')
call doit('world')
end

The thing is, there isn't such an animal (at least as noted up thru F95)
as a variable-length CHARACTER array defined as a varying allocated
length of each element in the array; Fortran doesn't have "jagged" arrays.

I'll let somebody who knows talk about anything later or you can dig
through the Intel documentation for CHARACTER variables to see what it
allows beyond F95, if anything.

--
From: Ron Shepard on
In article <hudstj$rib$1(a)news.albasani.net>,
Jovan Cormac <limulus(a)gmx.net> wrote:

> After all,
>
> WRITE(*,*) 'Hello', ' ', 'world'
>
> will do just what I described (without any additional processing, of
> course), so technically, it is certainly possible.

You can do the same with subroutine arguments. If you pass them
individually, and not as an array, then they all have their own length,
and that length is not modified during the subprogram call. You can
determine the length of each within the subroutine, but you can't change
it.

Your problem is that you are using a single array to pass all of the
character variables, and all of the elements of an array must have the
same length.

So one workaround is to not use an array but rather to use scalar
arguments. You can write the subprogram so that it accepts some large
fixed number of scalar arguments (but not an unlimited number). You can
make the arguments optional, which allows you to pass an arbitrary
number (within the allowed range). You can test within the subprogram
to see how many and which arguments are passed and to avoid referencing
the arguments that were not present.

You can also have an array of a derived type that has a pointer to a
character string. These pointers can point to strings of different
lengths. In this way you can still have an array, and you can have
elements of the array that point to strings of different length. You
might want to do this within the above subprogram, or you might want to
move this kind of data structure higher in your code and use it
directly. This should have been a feature of f90 when all the other
pointer and allocation capability was added, but it wasn't. But it was
added in one of the newer revisions (2003 or 2008), I forget which. It
is not something that is widely supported yet, so I don't use it for
portability reasons. But if you aren't concerned about portability, and
if your compiler supports this feature, then you might find it useful.
Maybe someone else who has used this feature can discuss some of its
advantages and disadvantages (and correct any mistakes in the above
description).

So I think there are several ways to achieve what you want to do, it
just depends on exactly what you want to do.

$.02 -Ron Shepard
From: Jovan Cormac on
Ron Shepard wrote:

> So one workaround is to not use an array but rather to use scalar
> arguments. You can write the subprogram so that it accepts some large
> fixed number of scalar arguments (but not an unlimited number). You can
> make the arguments optional, which allows you to pass an arbitrary
> number (within the allowed range). You can test within the subprogram
> to see how many and which arguments are passed and to avoid referencing
> the arguments that were not present.



That, sir, is a fantastic idea. I truthfully never though of that. I
could make my subroutine accept, say, 16 arguments (which I believe will
always be enough), and, through the optional thing, make it look as if
the number of arguments was actually variable.

That way, all problems with compiler differences will be gone as well,
since gfortran supports optional arguments.

Thank you very kindly & have a great day. Thanks also to everyone else
who tried to help, I appreciate it!

--
-- jovan
From: dpb on
dpb wrote:
....

> The assumed-length character argument CHARACTER*(*) _DOES_ take on the
> length of the argument passed in the subroutine so, technically, it does
> what you asked for. That is,
>
> subroutine doit(string)
> character*(*) string
>
> write(*,*) len(string)
> end
>
> would give 5,1,5 as the output if called as
>
> program showit
> call doit('Hello')
> call doit(' ')
> call doit('world')
> end
>
> The thing is, there isn't such an animal (at least as noted up thru F95)
> as a variable-length CHARACTER array defined as a varying allocated
> length of each element in the array; Fortran doesn't have "jagged" arrays.

BTW, one minor modification you could make in the above example if the
strings _were_ in an array would be sotoo--

program showit
character(len=5):: str(3)

str = (/ 'Hello', ' ', 'world' /)

do i = 1, 3
call doit(str(i)(:min(1,len_trim(str(i)))
end do
end

This would pass the full length of the trimmed string but a blank string
would be required to have a length of one instead of being of length zero.

Not exactly "without additional processing" but the processing is on
qualifying the input to the subroutine, not inside it. Of course, one
could do the same thing inside the routine itself, but this way inside
the routine the string array appears to have been variable length.

The limitation this way as opposed to doing the same thing inside the
routine is that only one element is in the routine at a time instead of
the array.

All depends, as Richard says, on what your needs really are.

But to paraphrase another common answer when features or behavior in
Fortran isn't what other language(s) might be is that Fortran CHARACTER
variables/arrays aren't BASIC variable-length strings. :) (There's a
lot of technical jargon that could be thrown in about what's different
in implementation and why they behave as they do, but the upshot is it
doesn't really matter when come right down to it--each is what it is).

HTH...

--
First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6 7
Prev: many runs in one directory
Next: pressure and fortran