pointers to arrays

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
Tiuri
User
User
Posts: 20
Joined: Fri Aug 15, 2003 2:44 am
Location: Canberra, Australia

pointers to arrays

Post by Tiuri »

As far as I understand PB currently only supports pointers to structures, labels and procedures. I would like to be able to pass a pointer to an array to a procedure, because procedures that perform an action on an array can be very useful.

I am looking for something like

Dim array.l(100)
Dim brray.l(100)
.
myprocedure(array())
myprocedure(brray())
.
Procedure myprocedure(*myarray.l[]) ; (invented syntax)
.
.
*myarray(i) = *myarray(i+1)/2 ; example array usage
.
EndProcedure

I found a workaround posted on the forum some time ago. This involves declaring a structure STRUC containing a single variable of the same type as the array, passing the pointer to the first array variable (Array()) to the procedure as a pointer to STRUC and doing your own pointer arithmetic in the procedure.
This is can become very cumbersome if your procedure contains many statements of the type

d2ydx(i)=(y(i+1)+y(i-1)-2*y(i))/(x(i+1)-x(i-1))

which are quite common in mathematical or scientific procedures. I am trying to convert a Fast Fourier Transform algorithm into PB, and this inability to pass arrays to procedures and then treat them like normal arrays inside the procedure is quite frustrating.
The alternative of putting an array in a structure also has difficulties, since in that case you can only pass an array with a single size, wheras you would like your procedure to work on arrays of any size.

Anyway, I think support for passing array pointers to procedures in the sense illustrated above would make PB much more attractive as a general language that is also suitable for more technical calculations.

PS. If somebody has come up with a good way of dealing with this using the current version of PB I would appreciate hearing about it.
Tiuri
User
User
Posts: 20
Joined: Fri Aug 15, 2003 2:44 am
Location: Canberra, Australia

Post by Tiuri »

Below a short program to demonstrate what is currently my best workaround trick for the problems mentioned above. Probably the solution is extremely obvious to everybody else, but maybe I will save somebody some time.

Code: Select all

Structure FakeArray
x.l[4194304]     ; array of size larger than you ever will use                 
EndStructure   ; large size doesn't matter,no instance will ever be created
;
Procedure showmod(*array.FakeArray,n.l)
  For i=0 To n
    Print(Str(*array\x[i])+"  ")  ; show elements of modified array
  Next
  PrintN("")
EndProcedure
;
Procedure show(*array.FakeArray,n.l)
  For i=0 To n
    Print(Str(*array\x[i])+"  ")  ; show elements of passed array
    *array\x[i]+10                ; modify elements of passed array
  Next
  PrintN("")  
  showmod(*array,n)                 ; pass on to next procedure by reference
EndProcedure
;
OpenConsole()
PrintN("Testing array passing")
;
Dim a.l(10)    ;declare array in main program

n=10
For i=0 To n : a(i)=i :Next  ; give array elements value
show(a(),n)                   ; pass array to first procedure by reference
For i=0 To n
  Print(Str(a(i))+"  ")       ; test that original array has really been modified
Next
;  
n.l=Val(Input())
CloseConsole()
End
I still would like to see a proper way of doing this though, since it relies on the compiler not doing any type testing (i.e. the variable passed is not really of type pointer to FakeArray)
talun
User
User
Posts: 28
Joined: Mon May 05, 2003 3:53 pm
Location: Italy

Post by talun »

Hi Tiuri,
array scope is always global in PureBasic code.
------------------- From PureBasic help ---------------------------------------
Dim is used to 'size' the new arrays. An array in PureBasic can be of any types, including structured, and user defined types. Once an array is 'sized' it can be resized but its content will be deleted. Arrays are dynamically allocated which means than a variable or an expression can be used to size them.

Arrays are always globally accessable in PureBasic. This means that they can always be accessed from inside procedures without needing to use the Global or Shared commands
-----------------------------------------------------------------------------------

try this little piece of code:

Code: Select all

Declare myprocedure()

Dim array.l(10) 
 
For x.l = 0 To 10
  array(x) = x
Next x
  
Debug "---------- Before... -------"
For x.l = 0 To 10
  Debug array(x)
Next x

myprocedure() 

Debug " -------- After... -----------"
For x.l = 0 To 10
  Debug array(x)
Next x

End

Procedure myprocedure() 
 
  For i.l = 0 To 10
    array(i) = array(i) * 2
  Next i

EndProcedure 
I hope this help you

Bye
Sergio
Tiuri
User
User
Posts: 20
Joined: Fri Aug 15, 2003 2:44 am
Location: Canberra, Australia

Post by Tiuri »

Hi Sergio,
thanks for your reply. I was aware that arrays in PB are always global, but I think there are several circumstances where being able to pass an array as a pointer still is very useful.

The first is that you may want to apply the procedure to different arrays in your application. For instance you could write a procedure to calculate the sum of all elements in an array. If you can pass the array as a pointer, you only have to write one such procedure and you can then apply it to all arrays in you programs. If you would just rely on the globality of arrays, you would have to write a procedure or code for every individual array.

The second one is reuse of procedures in different applications. If you could not pass a pointer, you would have to change the names of the array variables every time you want to use the procedure to match the array name in the main application.
talun
User
User
Posts: 28
Joined: Mon May 05, 2003 3:53 pm
Location: Italy

Post by talun »

Hi Tiuri, I completely agree with you and maybe you know my old post related to this argument
viewtopic.php?t=2582&highlight=talun.
If you allow me an off-topic suggestion, be careful with the results related to "complex" calculations in PureBASIC (eigenvalues, FFT, high precision trigonometry and so on). See also the Geoff's posts:

viewtopic.php?t=5071&highlight=geoff
viewtopic.php?t=5705&highlight=geoff

Bye
Sergio
Pupil
Enthusiast
Enthusiast
Posts: 715
Joined: Fri Apr 25, 2003 3:56 pm

Post by Pupil »

Maybe this can help?

Code: Select all

Structure FloatArrayType
  Val.f[0]
EndStructure

Procedure DoStuff(*p.FloatArrayType, max.l)
  For i = 0 To max
    Debug StrF(*p\Val[i])
  Next
EndProcedure

Dim array.f(100)

For i = 0 To 100
  array(i) = i
Next

DoStuff(@array(), 100)
Pupil
Enthusiast
Enthusiast
Posts: 715
Joined: Fri Apr 25, 2003 3:56 pm

Post by Pupil »

Or this?

Code: Select all

Dim array.f(100)
Dim tmp.f(0)

Procedure DoStuff(*ptr, max.l)
  oldaddress.l = @tmp()
  tmp() = *ptr
  For i = 0 To max
    Debug StrF(tmp(i))
  Next
  tmp() = oldaddress
EndProcedure


For i = 0 To 100
  array(i) = i
Next

DoStuff(@array(), 100)
Be carefull if trying this with threads that access the same array!
Tiuri
User
User
Posts: 20
Joined: Fri Aug 15, 2003 2:44 am
Location: Canberra, Australia

Post by Tiuri »

Thank you again for your comments.
Talun: I did see some of the posts you refererred to, and now that I look at them better Tinman already used the method I illustrated above. Sorry about that. The one you liked by Danilo did not declare an array in the structure, so that you could not do things like y(i)=x(i+1)+x(i-1) and this is what stuck in my mind
The r10 library looks very impressive but is over my head since I do not understand assembler. I hope that the PB version with 64 or 80 bit floats will be available soon.

Pupil: Thanks for pointing out that you can in fact declare a dummy array of zero length. I would have thought that the debugger would complain about arrays being used with an index outside the allowed range, but somehow that doesn't happen. I am even more surprised that this doesn't happen in your second example, and that an expression like tmp()=*ptr is allowed. What I like about the second example is that you can use the standard compact array syntax a(i) in your routine instead of *a\x. An advantage of the first one is that you don't have to define a separate dummy array for each array pointer you want to pass to the procedure (if you want to pass multiple arrays).

By the way, I think you get the pointer to an array from array(), you don't have to prefix@

Now that we are discussing this, I noticed that the intrinsic PB function SortArray also takes an array pointer as input, but you don't have to specify either the size or type explicitly. Does that mean there is a way to determine these array properties inside your procedure? Does anybody know how to do that?
hellhound66
Enthusiast
Enthusiast
Posts: 119
Joined: Tue Feb 21, 2006 12:37 pm

Post by hellhound66 »

Removed.
Post Reply