Arbitrary sized array

Hi all
I am gonna declare an arbitrary sized one dimensional array in fortran so that the size of array will specify
by user input. i can not use syntax below:

program main
integer :: n
print *, “Enter a positive integer number:”
read *, n
real, dimension(n) :: a



end program main

You need an allocatable array. Its size is determined at run-time:

program main
  implicit none
  integer :: n
  real, allocatable, dimension(:) :: a
  print *, “Enter a positive integer number:”
  read *, n
  ...
  allocate(a(n))
  … ! work with a 
  deallocate(a)
  ...
end program main

So you declare your array as allocatable, and then explicitly allocate it with the size you want. When you’re done working with it, deallocate it to free the memory.

If you prefer, you can also omit the dimension attribute and declare the array like this:

real, allocatable :: a(:)

It’s a good habit to always include implicit none at the beginning of your program.

2 Likes

No, you need first to declare the array as allocatable, then allocate memory once the size is known:

real, dimension(:), allocatable :: a
read *,n
allocate(a(1:n))
2 Likes

Thanks :pray: :pray: :pray:

Thank you :pray: :pray: :pray:

Yes! Didn’t spot that. Fixed.

1 Like

Final program:

1 Like

Nice! Now, if you’d like to go for a v2, try:

  1. Prompting the user for n without resorting to a goto;
  2. Using intrinsic functions minval and maxval.
1 Like

Nice suggestions :+1:

By the way, starting with Fortran 2008 and the introduction of the BLOCK construct, it’s also possible to employ an “automatic” array which may be of interest to some readers. Here’s an example: note the automatic array has the scope of the BLOCK construct.

   integer :: n
   print *, "Enter a positive value for n"
   read *, n
   print *, "you entered n=", n
   block
      integer :: a(n)
      integer :: i
      a = [( i, i=1, n )]
      print *, "a = ", a
   end block
end

Here’s the processor response to this example

C:\Temp>type p.f90
integer :: n
print *, “Enter a positive value for n”
read *, n
print *, “you entered n=”, n
block
integer :: a(n)
integer :: i
a = [( i, i=1, n )]
print *, "a = ", a
end block
end

C:\Temp>gfortran -Wall p.f90 -o p.exe

C:\Temp>p.exe
Enter a positive value for n
5
you entered n= 5
a = 1 2 3 4 5

C:\Temp>

3 Likes

Interesting, can you tell us what are the purposes of BLOCK…END BLOCK ?

1 Like

@ELNS
A piece of code without goto (I don’t want to troll about goto :wink: but I think the code will be clearer because of the indentation):

    do
        print *, "Enter a positive value for n"
        read *, n
        if (n > 0) exit
    end do

Note that in Fortran there is no repeat...until or do...while (with the while at the end) loops.
You could of course also use the old trick:

    n = -1
    do while (n<=0)
        print *, "Enter a positive value for n"
        read *, n
    end do

But this is less elegant than the exit solution because the statement n=-1 is arbitrary: n=-2020 or n=-314159265 would do the job as well. If the language offers an elegant solution then use it, if it does not, find a trick.
Note that there is also the cycle statement to go to the next iteration of a loop.

1 Like

My understanding is that the block construct simply allows programmers to organise code by grouping declarations and statements together within a defined local scope. This can have some advantages:

  • It avoids large declaration blocks at the beginning of programs and procedures;

  • it is easier to reason which variables are used in which execution statements when reading the code;

  • it limits the scope of variables so they can’t accidentally be used elsewhere;

  • it can be useful for objects with finalizers since these will be called at end block if the objects are declared within the block.

I don’t believe there is any tacit memory or speed advantage to using block constructs, they are just for programmer comfort.
The main argument against using block constructs IMHO is that a procedure would provide the same advantages in terms of code organisation, while also being reusable (callable) whereas a block construct is not.

3 Likes

Thank you @lkedward for that answer. Do you think there could be a speed impairment if a block is repeated a lot of time in a loop ? (if its variables need to be allocated at each iteration)

1 Like

I would expect a slow down if you are declaring large arrays with dimensions only known at runtime (just like @parekhvs’s example above) - though this is true regardless of if you’re using a block construct.

However if the variables are scalar or the array size is a compile-time constant, then I would expect the compiler to be able to optimise this (i.e. allocate once). Unfortunately I’m no compiler expert, so this is my best guess.

2 Likes

If you want to have thread-local variables inside a do concurrent you have to use the block construct.

2 Likes

Another great usage of block that @lkedward pointed out to me is to prevent name clashes between intrinsic functions and named variables by introducing a new local scope. An example can be found in the discussion Best practices for passing C strings.

2 Likes

Would that approach be equivalent to using the LOCAL clause to specify variable locality in DO CONCURRENT?

e.g.

do concurrent (i=1,10) local(x)
...
1 Like

I didn’t know about that addition for 2018 so thanks for the heads-up. The syntax seems to be very similar to that of openmp (a good thing). Nevertheless I’d say that the block construct gives you more, particularly if there are many variables or more sophisticated initializations.

do concurrent (i=1,10)
    block
        integer :: a, b
        call load_start_values(a,b)
        ....
    end block
end do
2 Likes

I agree - I don’t use do concurrent but my experience with OpenMP is that the locality clauses can quickly get long; by comparison the block construct is much cleaner and more readable.

1 Like