DIM statement   

Purpose

Declare and dimension arrays, scalar variables, and pointers.

Syntax

Arrays:

DIM var[(subscripts)] [AS [GLOBAL | INSTANCE | LOCAL | STATIC | THREADED]type] [PTR | POINTER] [AT address] [, ...]

DIM var[(subscripts)] ' var may include a type-specifier

Scalar variables:

DIM var AS [GLOBAL | INSTANCE | LOCAL | STATIC | THREADED] type [PTR |POINTER] [, ...]

DIM var  ' var must include a type-specifier

Remarks

DIM declares var to be a variable or array whose type is specified by appending a type-specifier to the name or by using the AS type keyword.  If the AS clause is used, the variable name cannot end with a type-specifier character.

DIM can only be used inside a SUB, FUNCTION, METHOD, or PROPERTY.  Outside of Subs, Functions, Methods, or Properties, use GLOBAL or INSTANCE to declare variables and arrays.

DIM can also be used to dimension an "absolute array" - one that occupies a specific location in memory.  This can be useful to dynamically "superimpose" one type of array directly over the top of an existing block of memory (which could be another type of array, or data structure).  This would form a Union-like overlay structure.  See below.

In addition, it is possible to create an array of pointers with the DIM statement, and it is also possible to do so at a specific location in memory.  This is termed an "absolute pointer array".

Dimensioning arrays

subscripts may take one of the following forms for each array dimensioned:

(a) A comma-delimited list of one or more Long-integer expressions, each defining a dimension of the array.  This form is used to declare arrays whose subscript (index) range starts at 0.  For example, the following lines are equivalent ways of dimensioning the same array:

DIM lArray(20) AS LONG  ' With an AS type clause

or

DIM lArray&(20)         ' With a type-specifier

Both lines above define a one dimension Long-integer array that has 21 elements, from lArray(0) to lArray(20) inclusive.  The second line uses a type-specifier symbol to specify the data type, and this uses a simplified syntax (trailing clauses/keywords are not permitted).  The simplified syntax is only valid for data types that have a type-specifier symbol ($, !, @, @@, #, ##, %, &, &&, ?, ??, ???), or the specifier can be omitted if there is a DEFtype statement in effect.  The specifier must be omitted if #DIM ALL is in effect.

Declarations of multiple-dimension arrays take the following forms:

DIM sArray(20,40,2) AS STRING

or

DIM sArray$(20,40,2)

These two lines of code define a dynamic string array with three dimensions, 21 elements by 41 elements by 3 elements, totaling 2583 string elements.  As before, the second line uses the simplified syntax form.

(b) A comma-delimited list where both the upper and lower subscript bounds are explicitly declared for each dimension of the array.  For each dimension, the lower bound is listed first, followed by the TO keyword, followed by the upper bound.  For example:

DIM MyArray(1 TO 20) AS LONG

defines an array of one dimension that has 20 elements, from MyArray(1) to MyArray(20).  The lower bound does not have to be zero or one; for example:

DIM SalesByYear(1980 TO 2000) AS INTEGER

or

DIM SalesByYear%(1980 TO 2000)

Each array can access elements in the range of -2,147,483,648 to 2,147,483,647.  It is recommended that an explicit variable scope clause (GLOBAL/LOCAL/STATIC) be added to each DIM statement that uses an explicit type clause.  See Restrictions below.

Array Initialization and Absolute Arrays

PowerBASIC generates an error message when it encounters an array that hasn't been dimensioned.  If the array has already been dimensioned, the DIM statement is ignored.  A new array is not created and a run-time error is not generated.

When a program is first executed, PowerBASIC sets each element of a numeric array to zero, and sets each element of regular string arrays to a null string (length zero).  However, when an absolute array is Dimensioned (at a specific location in memory using the AT address syntax), PowerBASIC does not initialize the memory occupied by the array.  Further, when an absolute array is erased, the memory is not released either.  This provides a powerful mechanism to create Union-like overlay structures in memory.

The most common use of an absolute array is when manipulating Visual Basic arrays directly from a DLL.  This involves obtaining a pointer to the array, the element size, and the number of elements.  With this information, an absolute array can be dimensioned in PowerBASIC and the array memory manipulated directly.  Another common use involves using a large dynamic or fixed-length string memory block, overlaid with an absolute numeric array.

Care must be exercised when using absolute arrays, since the contents of an absolute array can only be valid for the scope of the memory the array references.  If an absolute array references memory that is LOCAL to the procedure, the array contents become invalidated if the target memory block is released.  For example, by either explicitly deallocating the memory block, or exiting the procedure itself.  Attempting to access absolute array memory that has been deallocated will likely trigger a General Protection Fault (GPF).  On this basis, absolute arrays should be LOCAL to the procedure in which they are to be used.

While PowerBASIC supports LBOUND values that are non-zero, PowerBASIC generates the most efficient code if the LBOUND parameter is omitted (i.e., the array uses the default LBOUND of zero).  You should also avoid specifying an explicit LBOUND of zero, since this imposes a small efficiency penalty with no meaningful benefits

Declaring scalar (non-array) variables

If you have specified #DIM ALL or OPTION EXPLICIT, you have to declare all variables used in your programs.  PowerBASIC provides a variation of the DIM statement for this job, because of the reduced level of syntax required for scalar variables.  The following is a simplified syntax for DIM that just applies to scalar variables: 

DIM var AS [GLOBAL | INSTANCE | LOCAL | STATIC | THREADED] type [PTR | POINTER] [, ...]

DIM var   ' var must include a type-specifier

Here are some sample variable declarations:

DIM a AS LOCAL INTEGER

DIM b AS STATIC WORD

DIM c AS GLOBAL DOUBLE POINTER

DIM d AS ASCIIZ * 255

DIM e AS THREADED STRING
DIM f AS INSTANCE SINGLE
 

AS type

Type

BYTE

Byte

WORD

Word

INTEGER

Integer

DWORD

Double-word

LONG

Long-integer

QUAD

Quad-integer

SINGLE

Single-precision floating-point

DOUBLE

Double-precision floating-point

EXT

Extended-precision floating-point

EXTENDED

Extended-precision floating-point

CUR

Currency

CURRENCY

Currency

CUX

Extended-currency

CURRENCYX

Extended-currency

STRING

Dynamic (variable-length) string

WSTRING

Unicode Dynamic string

STRING * x

Fixed-length string

ASCIIZ * x

Nul-terminated string

ASCIZ * x

Nul-terminated string

STRINGZ * x

Nul-terminated string

WSTRINGZ * x

Unicode Nul-Terminated string

Pointer

Pointer

Ptr

Pointer

VARIANT

Variant

IAUTOMATION

Automation Interface

IDISPATCH

Dispatch Interface

IUNKNOWN

Direct Interface

GUID

16-byte GUID string

FIELD

Field string

Restrictions

LOCAL ASCIIZ, LOCAL fixed-length strings, and LOCAL UDTs are created on the stack frame of the Sub/Function/Method/Property in which they are declared. You must therefore use caution so that the combined local variable size does not exceed the allocated stack size. Unless you declare otherwise, PowerBASIC sets a default stack size of 1MB. If more stack space is required, you can allocate it with the #STACK metastament. There are no such limitations with GLOBAL, INSTANCE, THREADED, or STATIC variables.

When a DIM statement is used (without an explicit scope clause), to declare a variable in a procedure, and an identical variable has already been declared as GLOBAL, the variable in the procedure will be given GLOBAL scope.  For example:

GLOBAL xyz AS LONG

[statements]

SUB MySub

  DIM xyz AS LONG

  ' Here, xyz is a GLOBAL variable

END SUB

To ensure that the variable scope is LOCAL to the Sub/Function/Method/Property, use a LOCAL statement rather than a DIM statement.  Alternatively, add an explicit scope clause to the DIM statement.  For example:

GLOBAL xyz AS LONG

[statements]

SUB MySub

  DIM xyz AS LOCAL LONG

  ' Here, xyz is a LOCAL variable

END SUB

Declaring pointer variables

A pointer must be declared before it can be used.  You use the DIM statement to declare pointers, and describe the type of data to which they point.  When a pointer is declared, it is automatically initialized to a value of zero.  This is known as a null-pointer.  You must remember to initialize it to a valid address, or you will get a General Protection Fault (GPF).  The syntax for declaring pointer variables is similar to that of regular variables:

DIM var[(subscripts)] AS [GLOBAL | INSTANCE | LOCAL | STATIC | THREADED] type [PTR | POINTER] [, ...]

Here are some examples of pointer variable declarations:

DIM a        AS BYTE PTR

DIM b        AS INTEGER POINTER

DIM c        AS STRING PTR * 25

DIM d        AS MyType POINTER

DIM e(500)   AS INTEGER PTR

Pointers themselves are stored as DWORD values.

Options

The scope of a variable or array is set using the GLOBAL, INSTANCE, LOCAL, STATIC, or THREADED keywords.

Restrictions

When returning a pointer to a calling Sub, Function, Method, or Property, make sure the pointer target remains valid when the current routine terminates.  For example, returning a pointer to a LOCAL variable is certain to trigger a GPF, since local storage is released when the routine ends.  In this case, the pointers target should be STATIC, GLOBAL, or INSTANCE, or be valid within the scope of the calling code.

IAUTOMATION, IDISPATCH, IUNKNOWN, VARIANT and GUID variables have special uses with COM.

See also

#DIM, ARRAYATTR, ERASE, GLOBAL, INSTANCE, Just what is COM?, LOCAL, REDIM, RESET, STATIC, THREADED, VariablesVariable Scope, What is an object, anyway?