For Programmers: Free Programming Magazines  


Home > Archive > Fortran > October 2006 > arrays of variable size









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author arrays of variable size
optimizer

2006-10-23, 7:01 pm

Hi everybody
I am an Italian researcher in electrical engineering. Does anybody know
if it is possible to have an array of variable size? or at least is it
possible to resize an array? I try to explain my question with an
example:

program dummy

integer :: ndim
parameter(ndim=5)
real(8) :: vector(ndim)
vector=1d0 !vector is
(1d0,1d0,1d0,1d0,1d0)
....

ndim2=12
resize(vector,ndim2) !now vector is
(1d0,1d0,1d0,1d0,1d0,0d0,0d0)

....

end

Any help is welcome
Thank you in advance
Fabio

Mark Morss

2006-10-23, 7:01 pm

You can go:

REAL(8),ALLOCATABLE,DIMENSION(:) :: vector

Then having somehow obtained integer ndim, you can later (even in a
subroutine) go:

ALLOCATE (vector(ndim))

and work with your ndim-element vector. Then if you have some new
value of ndim, you can go:

DEALLOCATE (vector)
ALLOCATE (vector(ndim))

and work with an array of new size.

Another way to have variable-sized arrays is to use them in
subroutines, e.g.:

SUBROUTINE EXAMPLE(a,b,c)
IMPLICIT none

INTEGER, INTENT(in) :: a
REAL(8), DIMENSION(a) :: b
REAL(8), INTENT(out) :: c

...operations to set c

END SUBROUTINE EXAMPLE

Also if 'a' had been an array of known shape but arbitrary size, you
could have sized 'b' to a's shape using the SIZE function.

Finally, subroutines will work with arrays of arbitrary size, for
example,

SUBROUTINE SUMOF(b,c)

REAL(8), DIMENSION(:), INTENT(in) :: c
REAL(8), INTENT(out) :: c

c = 0.0
DO i = 1,SIZE(C)
c = c + b(i)
END DO
END SUBROUTINE SUMOF






optimizer wrote:
> Hi everybody
> I am an Italian researcher in electrical engineering. Does anybody know
> if it is possible to have an array of variable size? or at least is it
> possible to resize an array? I try to explain my question with an
> example:
>
> program dummy
>
> integer :: ndim
> parameter(ndim=5)
> real(8) :: vector(ndim)
> vector=1d0 !vector is
> (1d0,1d0,1d0,1d0,1d0)
> ...
>
> ndim2=12
> resize(vector,ndim2) !now vector is
> (1d0,1d0,1d0,1d0,1d0,0d0,0d0)
>
> ...
>
> end
>
> Any help is welcome
> Thank you in advance
> Fabio


Craig Powers

2006-10-23, 7:01 pm

Mark Morss wrote:
> You can go:
>
> REAL(8),ALLOCATABLE,DIMENSION(:) :: vector


Except that you should use either DOUBLE PRECISION or a soft-coded kind
obtained as either KIND(0.0d0) or from SELECTED_REAL_KIND, rather than
the non-portable hard-coded value of 8.
dpb

2006-10-23, 7:01 pm


optimizer wrote:
> Hi everybody
> I am an Italian researcher in electrical engineering. Does anybody know
> if it is possible to have an array of variable size? or at least is it
> possible to resize an array? I try to explain my question with an
> example:
>
> program dummy
>
> integer :: ndim
> parameter(ndim=5)
> real(8) :: vector(ndim)
> vector=1d0 !vector is
> (1d0,1d0,1d0,1d0,1d0)
> ...
>
> ndim2=12
> resize(vector,ndim2) !now vector is
> (1d0,1d0,1d0,1d0,1d0,0d0,0d0)
>
> ...


Not sure how ndim2 of value 12 relates to the example--looks more like
either ndim2 = 7 or maybe intended "ndim2 = ndim1 + 2", perhaps?

Either way, closest can do w/ F95 allocatable arrays is as Mark M
demonstrated -- once an ALLOCATABLE array is ALLOCATE'd, it can not be
reALLOCATE'd, only DEALLOCATE'd and then ALLOCATE'd anew. An
ALLOCATABLE array is uninitialized by an ALLOCATE statement, so to
"grow" an array and retain existing values one has to allocate a new
array of the desired size, initialize it w/ whatever value(s) desired,
and then copy the old data into it (not necessarily in that order, of
course, as long as don't overwrite data w/ subsequent initialization).

VisualBasic w/ ReDim Preserve has such as built in facility, but behind
the scenes it is likely required to do the same thing as the above
anyway so it's really little more than syntactic convenience.

optimizer

2006-10-30, 7:15 pm

Tahnk you all for the suggestions...
Just an additional doubt about Mark's notes
If I deallocate a vector and then I allocate it again with an increased
dimension

DEALLOCATE (vector)
ALLOCATE (vector(ndim))

I suppose there are two problems:
1) the additional elements must be initialized as noted by dbp (simple
problem with simple solution)
2) if the required space for the new allocation is greater than the
available contiguous space, the allocation will take another slot of
memory, with the subsequent loss of data.
Is 2) correct?
Because my piece of code deals with large vectors, I think that this
solution can be dangerous.
Again many thanks to all
Fabio

Fortran Learner

2006-10-30, 7:15 pm


optimizer wrote:
> Tahnk you all for the suggestions...
> Just an additional doubt about Mark's notes
> If I deallocate a vector and then I allocate it again with an increased
> dimension
>
> DEALLOCATE (vector)
> ALLOCATE (vector(ndim))
>
> I suppose there are two problems:
> 1) the additional elements must be initialized as noted by dbp (simple
> problem with simple solution)


Yes. Actually the initialized value is depend on your system. It's in
general equal to 0. But be careful, all the element would be
unavialable after you deallocate it.

> 2) if the required space for the new allocation is greater than the
> available contiguous space, the allocation will take another slot of
> memory, with the subsequent loss of data.
> Is 2) correct?


I don't think so here. If the space is inadequate, the program will
stop. So, if you indeed hava a very big array, you'd better to have a
bigger RAM, or you can using something like storage and exchange
scheme. :)
allocate and deallocate are a general technolgy in Fortran 90/95
codeing. So, I think it will have no such problem.

> Because my piece of code deals with large vectors, I think that this
> solution can be dangerous.
> Again many thanks to all
> Fabio


Les

2006-10-30, 7:15 pm


"Fortran Learner" <ding.xiaobin2004@gmail.com> wrote in message
news:1161772986.240714.37970@e3g2000cwe.googlegroups.com...
>
> optimizer wrote:
>
> Yes. Actually the initialized value is depend on your system. It's in
> general equal to 0. But be careful, all the element would be
> unavialable after you deallocate it.


If you aim to write portable software, and/or write software to be used by
others, and/or may in the future change your compiler then NEVER assume
initialisation of variables by the system (compiler, loader or whatever)
ALWAYS initialise variables yourself.
In fact you can remove all the words up to "then" in the above.
Much of my debugging over the past month has been due to uninitialised
variables. The original authors worked with a system that default
initialised to zero. Not so with our new system.

The concept of re-allocating arrays and retaining the original contents has
been covered here before but I will re-post a technique I use a lot in my
code.
(Note: the concept of "large vectors" is subjective. The code I work with
has "lots" of these re-allocatable arrays, and many of them in themselves
are "large" - for suitable definitions of lots and large.)

Hope this helps
Les

module AnExample
integer*4 :: Current_Size = 0
integer*4, pointer :: temp(:)
integer*4, allocatable, target :: temp_a(:)
integer*4, allocatable, target :: temp_b(:)
contains
!----------------------------------------------------------------------
SUBROUTINE AllocateTemp(Initial_size, ier)
implicit none
integer*4, intent(out) :: ier
integer*4, intent(in) :: Initial_size
ier = 0
allocate(temp_a(Initial_size),stat=ier)
if (ier == 0) then
Current_size = Initial_size
temp => temp_a
endif
end subroutine AllocateTemp
!----------------------------------------------------------------------
SUBROUTINE DeAllocateTemp(ier)
implicit none
integer*4, intent(out) :: ier
ier = 0
if (allocated(temp_a)) deallocate(temp_a,stat=ier)
if (allocated(temp_b)) deallocate(temp_b,stat=ier)

end subroutine DeAllocateTemp
!----------------------------------------------------------------------
SUBROUTINE ReAllocateTemp(newsize,ier)
integer*4, intent(out) :: ier
integer*4, intent(in) :: newsize
if (allocated(temp_a)) then
allocate(temp_b(newsize), stat=ier)
if (ier == 0) then
temp_b(1:Current_Size) = temp_a(1:Current_Size)
deallocate(temp_a, stat=ier)
temp => temp_b
endif
else
allocate(temp_a(newsize), stat=ier)
if (ier == 0) then
temp_a(1:Current_Size) = temp_b(1:Current_Size)
deallocate(temp_b, stat=ier)
temp => temp_a
endif
endif
if (ier == 0) then
Current_Size = newsize
endif
end subroutine ReAllocateTemp
end module AnExample


program main
use AnExample
implicit none
integer*4 :: Initial, Newsub
integer*4 :: ier


Initial = 100
call AllocateTemp(Initial,ier)
!..... test error code

!......... do stuff using array temp....

Newsub = 150
if (Newsub > Current_Size) then
call ReAllocateTemp(Newsub,ier)
! error handling code here
endif

....... do stuff using resized temp......
temp(Newsub) = 42

end



Craig Powers

2006-10-30, 7:15 pm

Fortran Learner wrote:
> optimizer wrote:
>
> Yes. Actually the initialized value is depend on your system. It's in
> general equal to 0. But be careful, all the element would be
> unavialable after you deallocate it.


It's in general not initialized at all unless you do so explicitly (as
stated and suggested by dpb), typically meaning that it has whatever was
in the location previously. That may or may not be zero -- in general,
it's better for you if it's not, because having it start at zero can
hide bugs that come back and bite you later.
dpb

2006-10-30, 7:15 pm


optimizer wrote:
....

> If I deallocate a vector and then I allocate it again with an increased
> dimension
>
> DEALLOCATE (vector)
> ALLOCATE (vector(ndim))


What I would say here is to forget about the concept of "again" in the
ALLOCATE step--the array storage is totally new and unrelated to the
previous storage. That the OS/rtl _might_ just happen to place the
beginning of the newly allocated memory and not reinitialize it would
be exactly that--pure happenstance.

> I suppose there are two problems:
> 1) the additional elements must be initialized as noted by dbp (simple
> problem with simple solution)


as well as the elements that are within the original size of the array
must also be initialized -- if you want that initialization to be the
same as the already existing values, then that has to be explicitly
arranged for.

> 2) if the required space for the new allocation is greater than the
> available contiguous space, the allocation will take another slot of
> memory, with the subsequent loss of data.
> Is 2) correct?


Even if there were enough contiguous memory available such that a new
allocation could be made with the starting location of the newly
allocated array in the same location as the previously deallocated
array, two things -- first, there is no guarantee the OS/rtl would
allocate that particular piece of memory, and second, the Standard
explicitly states that the newly allocated memory _wherever_ it happens
to be begins life uninitialized so.

The point is, the existing data are lost by the DEALLOCATE step
irregardless unless you take explicit steps to save them (which, in
essence, means utilizing a temporary array in some fashion to hold them
while the memory for the new array (which just happens to have the same
name in the source code) is ALLOCATE'd.

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com