How do i allocate an array of strings?

i have tried just doing:

character (len = :), dimension(:), allocatable :: menuButtons
...
allocate(menuButtons(3))

but this errors with

Error: Allocate-object at (1) with a deferred type parameter requires either a type-spec or SOURCE tag or a MOLD tag

You can only allocate arrays of fixed length strings

ie.

Character(LEN=132), Allocatable :: menuButtons(:)

To get an array of deferred length (ie allocatable) strings you have to embed them
in a derived type


Type DLstring_t
   Character(LEN=:), allocatable, :: aString
End Type

Type(DLstring_t), ALLOCATABLE :: DLstringArray(:)

Allocate(DLstringArray(50))
DLstringArray(1)%astring = "This is the first string"
DLstringArray(2)%astring = "Second string"

etc

3 Likes

oh ok, thanks

how do i index a string of a character array? this doesnt seem to work:

Menu_Init%menuButtons(i)(spaceIndex) = c_null_char

You only have to add a C null character if you are trying to pass strings to C. Fortran will know the length of the individual string components of the derived type. Just have to use the LEN or LEN_TRIM intrinsic functions to get the length. I believe that the need to add the null character for C_Interop will be removed in Fortran 2023 but don’t quote me on that.

As to your original question, you have to use the index in the embedded string name

ie

to add the c_null_char to the end of a string just append it
menu_Init%menuButtons(i)%pushMe = menu_init%menuButtons(i)%pushme//C_NULL_CHAR

To get to an individual character in a string you use the index notation
Print *,' character 3 = ', menu_init%menuButtons(i)%pushme(3:3)

but menuButtons is an array of strings not an array of a derived type

figured it out, i have to do this:

Menu_Init%menuButtons(i)(spaceIndex:spaceIndex) = c_null_char

@yeti0904 , @rwmsu :

The discussion above is not fully accurate.

The standard for Fortran does indeed support deferred-length allocatable CHARACTER intrinsic type that are allocatable arrays, the effective restriction is each element of character array must have the same allocated length.

Thus the above mentioned derived type becomes a solution when one seeks the so-called jagged arrays, that is where the length of each element needs to be different, say in a collection of color names “red”, “green”, “blue” where, say, you don’t want any blank padding

@yeti0904 , with your original post, if you can work with allocatable arrays of character type where each element must be or can be the same length with blank padding on elements of shorter relevant string data, then you can do so. For example, you can try the following:

   character(len=:), allocatable :: s(:)
   s = [ character(len=6) :: "abcd", "pq" , "uvwxyz" ]
   print *, s
end
3 Likes

@FortranFan

Yes you are correct, you can also (now) do

character(:), allocatable :: strings(:)
allocate(character(LEN=132) ::  strings(50))

The reason I didn’t mention it was that one compiler that shall remain nameless would gag on the above logic when deferred length strings were first introduced. Granted that was a while ago. For the things I use strings for, I prefer the jagged array approach so thats what I tend to recommend to people.

This was recently added to the quickstart tut:

2 Likes

I have the same question as this topic, but a bit more narrow for which FortranFan provided some explanation. I followed the link to the tutorial at fortran-lang.org that freevryheid supplied.

I see above the term “jagged array” used a couple times. I read on but found no “contextual clue” and the tutorial did not specifically add an example of “an allocatable array of strings” whose string length is not known at compile time. This does come up when wanting a copy of an array of strings.

The last piece of the tutorial part of “Arrays and strings” did not include an example which left me with a suspicion that it was either left out, or not possible, or my being clueless that my question’s answer should be sought in a different section.

However, I will attempt FortranFan’s “character(len=:), allocatable :: s(:)”

“Jagged array” refers to an array of dimension 2 or more. Imagine a two-dimensional array where the number of row varies by column. That is a jagged array.

In the case of a one-dimensional array of character values (string), the length of the character values is the second dimension. It is not a two-dimensional character array. More importantly, Fortran does not support jagged arrays. Nonetheless, you can create something much like a “jagged array” in Fortran by creating an array of a derived type, where the derived type values are arrays with different sizes or character values of different lengths.

So, in this discussion, posters are referring to such a character “jagged array”.

Why does this matter? Well, languages like Java, Python, and C support jagged arrays (really just arrays of arrays) closely. The indexing looks like a multidimensional array, but it is an array of arrays, in fact.

This distinction matters since memory addresses of a Fortran multidimensional array are contiguous, where the memory addresses of arrays of arrays are not necessarily contiguous. Accessing contiguous addresses is much faster, which is why true multidimensional Fortran arrays are still advantageous.

1 Like

Intel and GNU compilers used to have two orthogonal bugs for deferred length allocatable array of strings as dummy argument (or function output, if i remember correctly). If I bypassed it for one compiler, it would not compile with the other. That was several years ago of course, either or both might have been fixed by now.

@gWyche,

First, you can look up online on "jagged array"s. Here’s a link to a Wikipedia article on this that likely summarizes in one place what you already know but which may help you dig deeper into the topic, if you so choose.

The bottom-line is Fortran does not intrinsically support the concept, meaning in the context of arrays of CHARACTER intrinsic type - as I wrote above - “each element of character array must have the same allocated length.”

It is unclear from your post what pending questions or issues you have with Fortran and arrays of deferred-length (the one with : in the declaration) CHARACTER type. Did you try the example I provided above?

It may help you to make specific inquiries if you are running into any issues with your use of character strings in Fortran.

The only thing that would be required for fortran to “intrinsically” support the concept would be for an intrinsic derived type such as

type string_type
   character(:), allocatable :: s
end type string_type

to be defined. This could be either added as a new intrinsic type, always available, or it could be a derived type that is imported from, for example, iso_fortran_env or some other intrinsic module.

One might ask, if it is so easy for the programmer to define and use such a type, then why should it be included in the standard as a new intrinsic type? The reason is that when each programmer defines a derived type like this, say within a library, or within a set of interoperable modules, then it is problematic for those different libraries to work together. The programmer must copy and convert data from one library’s derived type to the other library’s derived type. If it is defined by the standard, then everyone would use the same intrinsic type and everything would be portable and interoperable. There might be a few other advantages too, such as the ability to do i/o directly on an array of jagged strings, rather than referencing them as components as is currently required. Another useful feature that could be added to the intrinsic type would be the ability to initialize the components as they are declared – it is currently not allowed to initialize any allocatable entity in fortran.

I am, and have been for a while, in favor of pushing this spec over the finish line: http://www.astro.wisc.edu/~townsend/resource/download/code/Fortran-ISO_VARYING_STRING.pdf

It would also even enable this syntax to “just work” (most likely):

type(varying_string), parameter :: options(*) = &
    [type(varying_string) :: "strings", "with", "varying", "lengths"]

The specs of the old ISO VARYING STRING are now outdated, not to mention that part (2) of the standard is now deleted, just like the CoCo preprocessor.

Reinstating that will be like forcing the mid-90s style BRICK size phones on certain kids when others have long moved on.

Additionally, as an intrinsic type, a Fortranner must demand freedom from type(..) enclosure in the declaration:

string, parameter :: options(*) = [ string :: "strings", .. ]
3 Likes

Maybe a bit, but I don’t think there is anything that fundamentally invalidates the overall approach, it just needs some updates.

Why? event_type, lock_type, etc. require type(). What’s so bad about the extra 6 characters?

They make needlessly verbose an already verbose language (adding the varying_ prefix makes the problem worse). IMO, it’s just bloat. Maybe even more importantly, it is confusing from a logical standpoint: why string should be different than integer? In all modern languages “varying strings” are first class data types, if I’m not wrong.

4 Likes