Pointer to Part of an Array

BlitzMax Forums/BlitzMax Beginners Area/Pointer to Part of an Array

Czar Flavius(Posted 2007) [#1]
I am trying to create a simulation of Conway's Game of Life.

(http://en.wikipedia.org/wiki/Conway's_Game_of_Life)

To do this I need two 2D arrays. One with the current state, and one to create the next generation state on. Then to create the subsequent generation, I must reverse the roles of the arrays so the second is the current generation, and the first is the next generation, and so on. (Similar to flipping in double-buffering).

So far I have made an array[x, y, 2]. The most obvious thing to do is create a variable which is either 0 or 1 to keep track of which array is which. However I was thinking of creating two pointers to the [x, y] part of the array, and not the [2] part. Then swapping around the pointers. So I can just use firstarray[x, y]. But I'm not sure how to do this exactly, or if it's a good solution.

Any advice will be appreciated. Thanks.


Dreamora(Posted 2007) [#2]
you can't

BM arrays are objects not continous int / float blocks.

If you need that use Banks instead.


Czar Flavius(Posted 2007) [#3]
In that case I think I'll stick with a chooser variable ;)


Gabriel(Posted 2007) [#4]
BM arrays are objects not continous int / float blocks.

Are you sure? That's not been my experience. Object Arrays are just an array of pointers, yes, but int and float arrays appear to be a block of contiguous memory. Granted you have to point inside the array ( Array[0] or Array[0,0] ) but the data does appear to be contiguous.

Proof of Concept:

Global IntArray:Int[,]=New Int[101,101]

Local B:Byte Ptr=Varptr(IntArray[50,50])
Print IntArray[50,53]
B[12]=2
Print IntArray[50,53]



Brucey(Posted 2007) [#5]
I'm with Gabriel on this one... from my experience, arrays of primitives (byte, short, int, float, double, long) appear to use contiguous memory.


ImaginaryHuman(Posted 2007) [#6]
What about arrays of arrays...

Local MyArray:Int[50][50][2]

Then you just need a variable that is either 0 or 1 which you use to refer to the third aspect of the array.

It's really an array of arrays of arrays.

Otherwise I would just use two separate 2d arrays and an if-else to jump between them.


FlameDuck(Posted 2007) [#7]
They often will appear to use contiguous memory - but don't count on it. These days memory fragmentation isn't as much of an issue (pretty much a non-issue really, especially on OSes with buddy-heap type memory managers) but you could conceivably create an array larger than your largest block of free memory. From what I can tell, BlitzMAX arrays are more like ArrayLists than traditional arrays.


ImaginaryHuman(Posted 2007) [#8]
I would recommend using banks as 2d arrays and accessing with pointers.


Azathoth(Posted 2007) [#9]
If you look at the source of some BRL modules, arrays are treated as contiguous memory, such as CurrentTime and CurrentDate of the System.mod uses local byte arrays and passes them by pointers to C functions.


TomToad(Posted 2007) [#10]
Why couldn't you just swap the array references like this?



Floyd(Posted 2007) [#11]
Or you could put all the update and draw stuff in a function which takes two arrays as input.

Then in the main loop you call this function with array1,array2 and then call it again with array2,array1.


Czar Flavius(Posted 2007) [#12]
Thanks for your suggestions! I think I will try something like TomToad's solution. I'll have two arrays and swap these two around after each generation.

Thanks again.


Gabriel(Posted 2007) [#13]
They often will appear to use contiguous memory - but don't count on it. These days memory fragmentation isn't as much of an issue (pretty much a non-issue really, especially on OSes with buddy-heap type memory managers) but you could conceivably create an array larger than your largest block of free memory.

So how is that different from C++? C++ programmers constantly rely on arrays being in blocks of contiguous memory, so why would BlitzMax be any more prone to creating an array larger than your largest block of free memory than C++ is?


SculptureOfSoul(Posted 2007) [#14]
Isn't an exception thrown or something if an array can't be allocated in contigous memory in C++?


Czar Flavius(Posted 2007) [#15]
long int array[999999999999999999999999999];

Anyone willing to try it? :)


Gabriel(Posted 2007) [#16]
Isn't an exception thrown or something if an array can't be allocated in contigous memory in C++?

Interesting thought. I've never experienced it, but then I've never experienced BlitzMax failing to allocate it in contiguous memory either. I'd like an official response from BRL if possible though, because my TrueVision modules is completely dependant on arrays using contiguous memory, and it's going to become bloody slow to do some things if I can't rely on it.


ImaginaryHuman(Posted 2007) [#17]
I've always assumed its contiguous as well. I seem to recall looking in the blitzmax module code and seeing the array type, with only one pointer to a block of memory. I didn't see any sign of a linked list or anything like that.
If they had a linked list they'd have to be checking within which link an array index lies before you can access it, which would be horrendous.


ImaginaryHuman(Posted 2007) [#18]
Found this line under the Blitz.mod in array.c file:

	arr=(BBArray*)bbGCAlloc( BBARRAYSIZE(size,dims),(BBGCPool*)&bbArrayClass );

This is part of the `new array` code, and allocates apparently a single block of memory for each `dimension`, unless I'm not interpreting it right - so maybe each dimension is stored together as one block of memory, and for a 1 dimensional array there is just one single block?

However, a look at blitz_memory.c is interesting, particularly in the bbGCMemAlloc subroutine.

e.g.
if( size>(MAXSIZE-SIZEALIGN) ){
		p=bbMemAlloc( size );

MAXSIZE is 256, so likelyhood is that bbMemAlloc will be called..., which calls:
b=malloc(size+4+SIZEALIGN);

So now we're into malloc(). I'm guessing therefore that you get a solid block of memory that's contiguous, at least for each dimension.

You'd think that it's supposed to be safe to get a pointer to the first element of the array and then access all the elements with the pointer, which would be seriously compromized if the contiguous indexes were split up into multiple memory sections. I would think Mark would've designed it so that where there are natural breaks, ie where you have an array of arrays or an array with more than one dimension, that the memory for those extra arrays or dimensions would be separate areas with their own `base pointers`. I don't think Mark would've overlooked the possibility that people would try to access array elements with pointers, which is a language feature, only to have it create creashes or array bounds exceptions for no reason that the user can find apparent.

Anyone know different?


ImaginaryHuman(Posted 2007) [#19]
Try this test program:
Local OneD:Int[1024*1024]	'4 megabytes of Int's
Print "Testing 4MB memory one-dimensional array"
'Test  continuity
Local Last:Int=Int(Varptr(OneD[0]))
Local Current:Int
Local Cont:Int=True
For Local Count:Int=1 To (1024*1024)-1
	Current=Int(Varptr(OneD[Count]))
	If Current<>Last+4
		Print "Last: "+Last+", Current: "+Current+", Discontinuous Memory!"
		Cont=False	
		WaitKey
	EndIf
	Last=Current
Next
If Cont=True Then Print "Memory was continuous!" Else Print "Memory was not continuous!"
Print "~nTesting two-dimensional array 1024x1024 (4 MB)"
Local TwoD:Int[1024,1024]	'4 megabytes of Int's
'Test  continuity
For Count=1 To 1024
	If Varptr(TwoD[Count-1,1023])<>Varptr(TwoD[Count,0])-4 Then Print "Separate memory for everything in ["+Count+",x]"
Next
Local Diff:Int=False
For Count=1 To 1024
	If Varptr(TwoD[0,Count-1])<>Varptr(TwoD[0,Count])-4
		Print "Separate memory within [0,"+Count+"]"
		Diff=True
	EndIf
Next
If Diff=True Then Print "Memory within dimension [0,x] is discontinuous" Else Print "Memory within dimension [0,x] is all continuous"

If this is correct and I'm interpreting it right, it suggests that:

a) For a one dimensional array, everything within that one dimension is in contiguous memory.
b) In a two-dimensional array, each of the first dimension elements points to a whole separate block of contigous memory which holds all of its children. So array[0,0] array[0,1] array[0,2] array [0,3] are all contigous, but array[0,0] array[1,0] and array[2,0] are separate memory areas. If you have more dimensions than 2 the same still applies, for each level, if there is a level below it, all of the contents of the below level are in a contiguous block of memory refereced by the current element in the current level.

The only thing this did not test is fragmented memory and whether this introduces a split.