Prev: many runs in one directory
Next: pressure and fortran
From: Richard Maine on 5 Jun 2010 12:42 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 5 Jun 2010 12:46 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 5 Jun 2010 13:02 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 5 Jun 2010 13:29 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 5 Jun 2010 13:29
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... -- |