Code Comments
Programming Forum and web based access to our favorite programming groups.Hi, I have a programming task that I've been unable to solve using standard fortran 90/95 language (although I was able to get it to work using Cray-style pointers. Can anyone think of an approach? I'm trying to write a general-purpose search routine to convert one set of codes to another. The conversion table is located on a tab-delimited file. The overall approach is: On first call, determine the length of the old code, length of the new code, and number of codes and dynamically allocate, fill, and sort the conversion table. On first and subsequent call, do a binary search on the table in memory to obtain the conversion information. The problem I've run into is the dynamically allocated table disappears between calls. When I add the SAVE attribute, I get an error message (using the Intel Fortran compiler). Any help will be greatly appreciated, Ron etQpredX@hotmail.com r e m o v e the Q and X Subroutine Convert(FieldOld,FieldNew,FilNam) Character(*) FieldOld,FieldNew,FilNam c c Stub to allow dynamic allocation of table c (since the length of passed parameters c must be known at time of routine entry) c LO = Len(FieldOld) LN = Len(FieldNew) Call Convert2 (FieldOld,FieldNew,FilNam,LO,LN) Return End c c The real subroutine c Subroutine Convert2 (FieldOld,FieldNew,FilNam,LO,LN) Character(*) FieldOld, FieldNew Character(*) FilNam Character(LO), Allocatable :: OldFieldTable(:) Character(LN), Allocatable :: NewFieldTable(:) c NOTE: Character(LN), Allocatable, Save :: NewFieldTable(:) c gets an error Data iFTS/1/ ! First time switch c If (iFTS.eq.0) go to 300 ! Check for first time procedure iFTS = 0 c c Count number of records Call CountNumberOfRecords (NumRec) c Allocate (OldFieldTable(NumRec)) ! Allocate memory Allocate (NewFieldTable(NumRec)) ! Allocate memory c c c Load Table c Call LoadTable(NumRec, FilNam, OldFieldTable, NewFieldTable) c c Sort table c Call CSORT (OldFieldTable,NewFieldTable,NumRec) c c Do binary search c 300 Continue c Call BSearch (NumRec, IndexMatch, FieldOld, OldFieldTable) FieldNew = NewFieldTable (IndexMatch) c c Return End
Post Follow-up to this messageMix1009 wrote: <snip> > Subroutine Convert2 (FieldOld,FieldNew,FilNam,LO,LN) > Character(*) FieldOld, FieldNew > Character(*) FilNam > Character(LO), Allocatable :: OldFieldTable(:) > Character(LN), Allocatable :: NewFieldTable(:) > c NOTE: Character(LN), Allocatable, Save :: NewFieldTable(:) > c gets an error I'm not sure of the particular part of the Fortran standard that prohibits this; but I'm guessing that your problems come from the fact that newFieldTable has a variable character length LN. If this array is SAVEd over subroutine calls, what happens then Convert2() is called with a different value of LN than previously? That there is ambiguity here, is a sure sign that you are doing something counter to the standard. Two possible fixes come to mind: a) use a constant for the character length. or b) declare NewFieldTable to be of type(VARYING_STRING), as defined in Part II (Varying length character strings) of the Fortran 95 standard. If you decide to do this, you will need an implementation of the ISO_VARYING_STRING module defined in Part II; you can download one such implementation (written by myself, bug reports welcome!) from: http://www.fortran.com/fortran/iso_varying_string.f95 cheers, Rich -- Dr Richard H D Townsend Bartol Research Institute University of Delaware [ Delete VOID for valid email address ]
Post Follow-up to this messageetpred@nocharge.com (Mix1009) writes: > The problem I've run into is the dynamically allocated table > disappears between calls. Yep. Non-saved things do that. With allocatable, they are *REQUIRED* to do that - it isn't up to the compiler. > When I add the SAVE attribute, I get an error message General advice. When reporting an error message, quote what it says instead of just saying "an eror message". In this case, I can deduce the problem anyway, but keep the advice in mind for the future. > Subroutine Convert2 (FieldOld,FieldNew,FilNam,LO,LN) ... > Character(LO), Allocatable :: OldFieldTable(:) The reason you get an error message when you add SAVE is (presumably) because OldFieldTable is an automatic variable - that is it depends on dummy arguments (LO). You can't have something that is both automatic and saved - they are contradictory. Automatic things are allocated with each subroutine call. The problem is that, in general, LO might be different from one call to another, in which case there would be a conflict between the saved data and the new declaration. True, your particular calls might happen to retain the same value of LO, but neither the compiler nor the standard treats that as a special case - it has to make sense in general. There is a fine solution in f2003. F2003 allows allocatable character length, so you could declare Character(:), Allocatable :: OldFieldTable(:) Now oldfieldtable is no longer automatic (we got rid of the dependence on LO - at least we moved it out of the declaration, which is what counts). Then specify the length in the allocate as Allocate (character(LO):: OldFieldTable(NumRec)) But that syntax for allocate is new to f2003; probably won't work in current compilers (unless they happen to have already implemented that f2003 feature - none have to my knowledge). For now, only 2 solutions occur to me off the top of my head. Neither seems particularly satisfactory, though probably either could be made to work. 1. Use a hard-wired character length instead of a dynamic one. You can still make the numrec dynamic - that's not the problem. This will work if you can specify some length that is both large enough so that it will work for all practical cases and small enough so that the memory cost won;t be excessive. You can still carry around the LO (and LN) variables so that you can refer to the substrings (1:LO) and (1:LN) when needed. 2. Use an array of characters instead of a character string. In your case, you have an array of strings, so turn that into a rank 2 array of characters (each of hard-wired length 1). Allocating arrays is fine in f90/f95. It is allocating character length that you can't do until f2003, so turn the character length into an array. While it can certainly work, this has the divantage that you can't use many of the handy string intrinsics on arrays of character. Also, you'd have to correspondingly change declarations elsewhere, which might be a bother, depending how many places that is. Oh yes... in writing the second option above, a 3rd one ocurred to me.. 3. Allocate as a rank 2 array of character*1, as in option 2. Then use sequence association to pass this allocated array as an actual argument to a dummy declared as a rank 1 array of strings. In order for the sequence association trick to work, the dummy has to be declared with adjustable array bounds and character length - do not use * as a character length and do not use assumed shape. I.e. the dummy declaration has to look something like Character(LO) :: OldFieldTable(numRec) where LO and numRec are both dummy args; you'd have to add LO (and LN) as args to a few of your lower-level routines. I consider this a bit of a hack, but it ought to work. Note that it does mean that the oldfieldtable is still a rank 2 array in the subroutine that allocate it - only in lower-level subroutines can you look at it as a rank 1 array of strings. Well... you might be able to hack up a trick with pointers, but that gets pretty subtle...enough so that I'd have to think a while to be sure it could work in this case. A lot simpler to just rewrite the one statement setting newfieldrec; that looks to be the only one really hit by this in the code you showed. -- Richard Maine | Good judgment comes from experience; email: my first.last at org.domain | experience comes from bad judgment. org: nasa, domain: gov | -- Mark Twain
Post Follow-up to this messageRich Townsend <rhdt@barVOIDtol.udel.edu> writes: > b) declare NewFieldTable to be of type(VARYING_STRING)... I forgot to mention that option. I might note that it is a variant of the general option of using an array of characters to replace a character string, but it has extra "stuff" (to use a technical term :-)) wrapped around it so that most of the nice character operations do sensible things. And implementors (such as Rich Townsend) have done the work involved in that extra stuff. -- Richard Maine | Good judgment comes from experience; email: my first.last at org.domain | experience comes from bad judgment. org: nasa, domain: gov | -- Mark Twain
Post Follow-up to this messageRichard E Maine wrote: > etpred@nocharge.com (Mix1009) writes: > Yep. Non-saved things do that. With allocatable, they are *REQUIRED* > to do that - it isn't up to the compiler. I was going to ask last wif allocatable arrays could be allocated in one subroutine, and deallocated in a called subroutine, or the other way around. It would seem from that that the second case doesn't work. For discussion purposes only, and not to get into any arguments, PL/I CONTROLLED (like allocatable) can be allocated/deallocated at any level (of subroutine nesting). Sort of like C's malloc/free, except that dimension information is also included. The question about contiguous allocation came from forgetting how assumed size and assumed shape work, and which one allocatable would be more like. -- glen
Post Follow-up to this messageOn 18 Oct 2004 10:17:37 -0700, etpred@nocharge.com (Mix1009) wrote: >The problem I've run into is the dynamically allocated table >disappears >between calls. When I add the SAVE attribute, I get an error message >(using the Intel Fortran compiler). The particular issue you ran into is that the variable in question is "automatic" diue to the character length being dependent on a dummy argument . Automatic variables cannot be SAVEd. Fortran 95 doesn't provide exactly wha t you want, which is a persistent array of run-time length character elements. I'll let others offer suggested alternatives. Steve Lionel Software Products Division Intel Corporation Nashua, NH User communities for Intel Software Development Products http://softwareforums.intel.com/ Intel Fortran Support http://developer.intel.com/software/products/support/
Post Follow-up to this messageglen herrmannsfeldt <gah@ugcs.caltech.edu> writes: > Richard E Maine wrote: > > I was going to ask last wif allocatable arrays could be > allocated in one subroutine, and deallocated in a called subroutine, > or the other way around. It would seem from that that the second > case doesn't work. Non-sequitur (I don't see the connection). The answer to your question is that yes, an allocatable can be allocated in one subroutine and deallocated in a called one, or the other way around. Both capabilities require the allocatable TR (or f2003) in order to allow a dummy argument to have the allocatable attribute. Or you can do it with the allocatable in a module or with host association; those work even in f90 without the TR. My "non-saved things do that" is a severe abbreviation of the actual conditions. Maybe you were taking it a bit more globally than I intended. Then I'd see the connection (but my statement isn't valid in the relevant contexts). To be more complete, I'd need to qualify it as something like "local" non-saved things and the define what I meant by local. SAVE never applies to dummy arguments, and things are a bit more complicated for variables in modules. So no, an allocatable dummy argument doesn't go away when you return just because it is non-saved (and you can't declare a dummy to be saved). -- Richard Maine | Good judgment comes from experience; email: my first.last at org.domain | experience comes from bad judgment. org: nasa, domain: gov | -- Mark Twain
Post Follow-up to this messageRichard E Maine wrote: > glen herrmannsfeldt <gah@ugcs.caltech.edu> writes: (snip) > The answer to your question is that yes, an allocatable can be > allocated in one subroutine and deallocated in a called one, or > the other way around. Both capabilities require the allocatable TR > (or f2003) in order to allow a dummy argument to have the allocatable > attribute. For the allocatableness (probably not a word) to be passed to the called subroutine? Does the caller need to know if the dummy has the allocatable attribute? > Or you can do it with the allocatable in a module or > with host association; those work even in f90 without the TR. > My "non-saved things do that" is a severe abbreviation of the actual > conditions. Maybe you were taking it a bit more globally than I > intended. Then I'd see the connection (but my statement isn't valid > in the relevant contexts). To be more complete, I'd need to qualify > it as something like "local" non-saved things and the define what I > meant by local. SAVE never applies to dummy arguments, and things are > a bit more complicated for variables in modules. So no, an > allocatable dummy argument doesn't go away when you return just > because it is non-saved (and you can't declare a dummy to be saved). If I understood a previous post, he wanted to allocate and initialize an array in a subroutine, and use it in the same routine called later. So, by adding it as a dummy argument and calling it with the appropriate (but otherwise unused) argument it would stay allocated? -- glen
Post Follow-up to this messageglen herrmannsfeldt <gah@ugcs.caltech.edu> writes: > Richard E Maine wrote: > > > For the allocatableness (probably not a word) to be passed to the > called subroutine? Does the caller need to know if the dummy > has the allocatable attribute? Yes. Specifically, the interface of th ecalled subroutine needs to be explicit (and that's why - so that the caller knows this.) > If I understood a previous post, he wanted to allocate and initialize > an array in a subroutine, and use it in the same routine called > later. So, by adding it as a dummy argument and calling it with > the appropriate (but otherwise unused) argument it would stay allocated? Yes. Exactly. -- Richard Maine | Good judgment comes from experience; email: my first.last at org.domain | experience comes from bad judgment. org: nasa, domain: gov | -- Mark Twain
Post Follow-up to this messageRichard E Maine wrote: > glen herrmannsfeldt <gah@ugcs.caltech.edu> writes: (snip) > Yes. Specifically, the interface of the called subroutine needs to > be explicit (and that's why - so that the caller knows this.) OK, same as PL/I. > Yes. Exactly. OK, PL/I has CONTROLLED INTERNAL which go out of scope when the routine ends. I believe the user is responsible for the FREE before return, though. CONTROLLED EXTERNAL is the global version, which stays allocated, and can be used from other routines with the same declaration. STATIC EXTERNAL is like Fortran COMMON. -- glen
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.