Re-dimensioning arrays
by Richard Russell, May 2014
BBC BASIC does not have a REDIM or REDIM PRESERVE statement, as found in some other dialects of BASIC (REDIM allows you to increase the dimensions of an existing array - the contents are lost - and REDIM PRESERVE allows you to increase the dimensions of an array without destroying its contents). However it is not difficult to provide an equivalent functionality using user-defined procedures (these are for BB4W, for BBCSDL see below):
DEF PROCredim1d(RETURN P%,S%,D%) LOCAL A% IF ?P%<>1 ERROR 14, "Bad use of array" IF P%<LOMEM OR P%>HIMEM SYS "GlobalFree", P% SYS "GlobalAlloc", 64, 5+S%*(D%+1) TO A% IF A%=0 ERROR 11, "DIM space" ?A%=1 : A%!1=D%+1 P% = A% ENDPROC DEF PROCredim2d(RETURN P%,S%,D%,E%) LOCAL A% IF ?P%<>2 ERROR 14, "Bad use of array" IF P%<LOMEM OR P%>HIMEM SYS "GlobalFree", P% SYS "GlobalAlloc", 64, 9+S%*(D%+1)*(E%+1) TO A% IF A%=0 ERROR 11, "DIM space" ?A%=2 : A%!1=D%+1 : A%!5=E%+1 P% = A% ENDPROC DEF PROCredimpreserve1d(RETURN P%,S%,D%) LOCAL A%,N%,O% IF ?P%<>1 ERROR 14, "Bad use of array" N% = 5+S%*(D%+1) O% = 5+S%*P%!1 SYS "GlobalAlloc", 64, N% TO A% IF A%=0 ERROR 11, "DIM space" IF N%>O% SWAP N%,O% SYS "RtlMoveMemory", A%, P%, N% A%!1=D%+1 IF P%<LOMEM OR P%>HIMEM SYS "GlobalFree", P% P% = A% ENDPROC DEF PROCredimpreserve2d(RETURN P%,S%,D%,E%) LOCAL A%,N%,O% IF ?P%<>2 ERROR 14, "Bad use of array" N% = 9+S%*(D%+1)*(E%+1) O% = 9+S%*P%!1*P%!5 SYS "GlobalAlloc", 64, N% TO A% IF A%=0 ERROR 11, "DIM space" IF N%>O% SWAP N%,O% SYS "RtlMoveMemory", A%, P%, N% A%!1=D%+1 : A%!5=E%+1 IF P%<LOMEM OR P%>HIMEM SYS "GlobalFree", P% P% = A% ENDPROC
The above procedures support 1-dimensional and 2-dimensional arrays; equivalent routines for arrays with more dimensions can be derived if required. If you REDIM PRESERVE a 2-dimensional (or more) array you should normally only change the first dimension; if you change another dimension the data will be 'preserved' but will appear to have moved. Note that it isn't usually sensible to reduce the size of an array.
In each case the parameters to the procedure are the name of the array, the size of each element of the array (see table below) and the required dimension(s). As with the normal DIM statement, the available indices run from zero to the specified value.
Here is a simple demonstration program:
DIM array(100) FOR I% = 0 TO 100 array(I%) = SQR(I%) NEXT PROCredimpreserve1d(array(), ^array(1)-^array(0), 200) FOR I% = 101 TO 200 array(I%) = SQR(I%) NEXT FOR I% = 0 TO 200 IF array(I%) <> SQR(I%) STOP NEXT PRINT "Test completed successfully" END
Note that if you REDIM (not REDIM PRESERVE) a string array you must explicitly empty the array first:
array$() = "" PROCredim1d(array$(), ^array$(1)-^array$(0), newsize%)
Here are equivalent procedures for BBC BASIC for SDL 2.0:
DEF PROCredim1d(RETURN p%%,S%,D%) LOCAL a%%,N% IF ?p%%<>1 ERROR 14, "Bad use of array" N% = 5+S%*(D%+1) IF p%%<LOMEM OR p%%>HIMEM SYS "SDL_free", p%% SYS "SDL_malloc", N% TO a%% IF @platform% AND &40 ELSE a%%=!^a%% IF a%%=0 ERROR 11, "DIM space" SYS "SDL_memset", a%%, 0, N% ?a%%=1 : a%%!1=D%+1 p%% = a%% ENDPROC DEF PROCredim2d(RETURN p%%,S%,D%,E%) LOCAL a%%,N% IF ?p%%<>2 ERROR 14, "Bad use of array" N% = 9+S%*(D%+1)*(E%+1) IF p%%<LOMEM OR p%%>HIMEM SYS "SDL_free", p%% SYS "SDL_malloc", N% TO a%% IF @platform% AND &40 ELSE a%%=!^a%% IF a%%=0 ERROR 11, "DIM space" SYS "SDL_memset", a%%, 0, N% ?a%%=2 : a%%!1=D%+1 : a%%!5=E%+1 p%% = a%% ENDPROC DEF PROCredimpreserve1d(RETURN p%%,S%,D%) LOCAL a%%,N%,O% IF ?p%%<>1 ERROR 14, "Bad use of array" N% = 5+S%*(D%+1) O% = 5+S%*p%%!1 SYS "SDL_malloc", N% TO a%% IF @platform% AND &40 ELSE a%%=!^a%% IF a%%=0 ERROR 11, "DIM space" SYS "SDL_memset", a%%, 0, N% IF N%>O% SWAP N%,O% SYS "SDL_memcpy", a%%, p%%, N% a%%!1=D%+1 IF p%%<LOMEM OR p%%>HIMEM SYS "SDL_free", p%% p%% = a%% ENDPROC DEF PROCredimpreserve2d(RETURN p%%,S%,D%,E%) LOCAL a%%,N%,O% IF ?p%%<>2 ERROR 14, "Bad use of array" N% = 9+S%*(D%+1)*(E%+1) O% = 9+S%*p%%!1*p%%!5 SYS "SDL_malloc", N% TO a%% IF @platform% AND &40 ELSE a%%=!^a%% IF a%%=0 ERROR 11, "DIM space" SYS "SDL_memset", a%%, 0, N% IF N%>O% SWAP N%,O% SYS "SDL_memcpy", a%%, p%%, N% a%%!1=D%+1 : a%%!5=E%+1 IF p%%<LOMEM OR p%%>HIMEM SYS "SDL_free", p%% p%% = a%% ENDPROC
The most reliable way of determining the element size is to calculate it at run-time, as in the above examples, but for reference here are the appropriate sizes for each type of array:
byte e.g. array&() | size=1 |
32-bit integer e.g. array%() | size=4 |
40-bit float e.g. array() | size=5 |
string e.g. array$() | size=6 |
64-bit float e.g. array#() | size=8 |
string e.g. array$() | size=8* |
64-bit integer e.g. array%%() | size=8* |
80-bit float e.g. array() | size=10* |
* BB4W version 6 or BBCSDL