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.
pointers to arrays
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.
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)
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
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:
I hope this help you
Bye
Sergio
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
Bye
Sergio
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.
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.
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
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
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)
Or this?
Be carefull if trying this with threads that access the same array!
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)
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?
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?