Arrays Near and Far

[ Frame-Free Link ]


Prologue

As a cold sun rises on Mars Colony, we find Don "Stinky" Boolean working feverishly at his terminal aboard an orbiting freighter. "Why won't this fraggin QuickBasic program work? I can't destroy Mars Colony without it!" screams Don. "Every time it runs I get the same fraggin message: 'Out of string space.' What does that mean? By all of Saturn's fraggin rings, what does it mean?!?"




Disclaimer

The opinions expressed by RudeJohn do not necessarily reflect those of the Basix Fanzineor its staff. In fact, they probably disagree with me entirely. Everyone else does. <sigh>




Arrays Less Than 64K

Microsoft's QuickBasic 4.5 compiler uses a 64K near-data segment named DGROUP for all ordinary variables, variable-length strings, and static arrays. When your program demands more string space than DGROUP can provide, you become the reluctant recipient of the dreaded "Out of string space" award. Check QuickBasic's online help regarding the FRE function, which may be used at run-time to determine the amount of memory available in DGROUP. Note that both static and dynamic variable-length string arrays are stored in DGROUP; there is no way to avoid this.
Other than for variable-length string arrays, dynamic arrays are always placed in far memory, i.e., (conventional) memory beyond DGROUP. Unfortunately, simply declaring an array to be dynamic has one major shortcoming: a size limit of 64K. On the other hand, the very next section explains how to create dynamic arrays greater than 64K, so just keep reading. And stop making that noise.
An array is declared as dynamic if you:
  1. Use the $DYNAMIC metacommand before declaring the array with DIM.
  2. Declare the array with REDIM.
  3. Declare the array with a variable or expression as a dimension.
  4. Declare the array in a SUB or FUNCTION.
Here are a few examples:
'$DYNAMIC
DIM Stinky( 666 ) AS INTEGER
'Dynamic array stored in far memory
'$STATIC
DIM Buffy( 69 ) AS LONG
'Static array, stored in DGROUP
REDIM TheAnswer$( 42 )
'Dynamic array of variable-length strings,
'stored in DGROUP no matter what!
Me% = 100
DIM Bite( Me% ) AS STRING * 100
'Dynamic array of fixed-length strings stored in far memory




Arrays Greater Than 64K

Arrays greater than 64K (64 * 1024 bytes = 65,536 bytes) are called huge arrays. Since arrays greater than 64K are stored in far memory, i.e., (conventional) memory beyond DGROUP, they are also dynamic. The nice thing about dynamic arrays is that they can be erased at run-time, thus freeing that amount of memory.
The /AH option, when used with either BC or QB, enables dynamic arrays of records, fixed-length strings, and numeric data to be larger than 64K each. Without the /AH option, the maximum size for each array is 64K. In addition, the size of the elements of a huge array _must_ be equal to a power of 2 (2, 4, 8, 16, 32, and so on) or the array will be limited to 128K.
Numeric data requires 2, 4, or 8 bytes depending upon its type. Thus, numeric arrays are always composed of elements whose size is equal to a power of 3... er, 2. Obviously, a variable-length string array can't be huge because its size is, by definition, unpredictable. <shrug> Fixed-length string arrays can be huge as long as the length of an element is defined to be equal to, you guessed it, a power of 2.
User-defined data types may require you to insert a dummy element in order to pad out the data type's total size. Consider the following:
TYPE MyRecord
LastName AS STRING * 25
FirstName AS STRING * 15
MiddleInit AS STRING * 1
Age AS INTEGER
GrossIncome AS LONG
END TYPE
This user-defined data type requires 25 + 15 + 1 + 2 + 4 = 47 bytes. The nearest power of 2 greater than 47 is 64 so we need to add 64 - 47 = 17 bytes to MyRecord in order to create a huge array. One way to accomplish this is to add a dummy string element as follows:
TYPE MyRecord
LastName AS STRING * 25
FirstName AS STRING * 15
MiddleInit AS STRING * 1
Age AS INTEGER
GrossIncome AS LONG
Pad AS STRING * 17
END TYPE
That's all there is to it. Now go forth and multiply!




Note

For a full-flavoured cup of steaming-hot rant regarding QuickBasic, MS-DOS memory models, and 80x86 architecture, take a slog through Why 64K?, available in this issue of the Basix Fanzine.




Epilogue

Fortunately for Mars Colony, Stinky never did get that pesky program running. Following a long string of unsuccessful attempts to become an interplanetary Bad Guy, Don finally saw the error of his ways and turned himself in to the authorities. Stinky is now happily serving out a life-sentence cleaning public toilets at Mars Station. If he keeps up the good work, he will eventually be allowed to use a brush. In about twenty years.

The End (?)



C'ya,
RudeJohn
"I'm rude. It's a job."


RudeWare | Papers | Projects | Fragments | Tutorials