Pointer, reference, array

Warning: incorrectly used pointers can cause instability and data corruption.

 

Tip: if you are looking for arrays, safe arrays are often the best choice.

Pointer variables

A pointer is a variable that holds address of other variable. Use operator & to get address of a variable or function. Use operator * to access variable to which pointer points. Examples:

 

 Declare variable v:
int v = 5
 Declare pointer p:
int* p = &v
 Now p points to (holds address of) v
int a = *p
 Now variable a = 5. This is the same as a = v
*p = 10
 Now variable v = 10. This is the same as v = 10

 Pass address of variable r to dll function:
RECT r
GetWindowRect(win() &r)

 Pass address of function TimerProc to dll function:
timeSetEvent 1000 10 &TimerProc 0 0

 

To declare a pointer variable, use type of variable to which it will point, and append *. For example, if you will use pointer p to hold address of a str variable, declaration must be str* p.

 

Maximal level of indirection is 3. For example, int*** p is OK, but int**** p is error.

 

A pointer variable is similar to an int variable. Like of int, the size is 4 bytes. Unlike int, it is interpreted as unsigned.

 

Operator * also can be used with enclosed expressions and functions that return pointer. Examples:

 

*(arr + 2) = 10
int i = *FunctionThatReturnsIntPointer

Arrays

A pointer can point to an array of variables. To access an array element, use operator []. Array indices begin with 0. If pointer points to array, it means that it points to the first variable in the array (the following two expressions are true: arr == &arr[0] and *arr == arr[0] ). If you add size of variable to the pointer (for example arr + sizeof(str)), the pointer will point to the next variable in the array ( arr == &arr[1] and *arr == arr[1] ).

 

You can create array in several ways:

 

1. Dynamic array allocated with intrinsic memory-allocation functions. Use _new or _resize to allocate or resize array. Use _delete to free it. These functions properly construct-destruct elements of any type. Example:

 

str* arr._new(10)
arr[0] = "abc"
str s = arr[9]
...
arr._delete

 

2. Dynamic array allocated with other functions (calloc, LocalAlloc, etc). Example:

 

word* arr = calloc(10 sizeof(word))
...
free arr

 

3. Dynamic array in str variable. QM automatically frees such array when str variable goes out of scope. Example:

 

str s.all(10*sizeof(word) 0 0)
word* arr = +s
...

 

4. Declare n local variables. Example:

 

str s0 s1 s2 s3
str* arr = &s0
...

 

5. Define variable type with embedded array. Example:

 

type LPSTRARRAY50 $s[50]
LPSTRARRAY50 a
lpstr* arr = &a[0]
...

 

6. Use safe array. Then you don't have to worry about array initialization and freeing.

 

 

In case 2 and 3, constructors and destructors for array elements are not called. For arrays of composite types (e.g. str), you must explicitly initialize array memory (calloc does it), and clear each element before freeing array memory. Example:

 

str* arr = calloc(10 sizeof(str))
...
for(int'i 0 10) arr[i].all
free arr

Reference variables

A reference variable holds address of other variable, but behaves syntactically like that variable. Usually it is initialized (receives address of other variable) when declaring. After that, it is used like normal variable. When various operations are performed with the reference variable, actually is modified the variable to which the reference variable points. Examples:

 

 Declare variable v:
int v = 5
 Declare reference r:
int& r = &v
 Now r is reference to (holds address of) v
int a = r
 Now variable a = 5. This is the same as a = v
r = 10
 Now variable v = 10. This is the same as v = 10

 

References can be [re]initialized later:

 

int& r
int v2=100
&r = &v2 ;;now r is reference to v2
out r ;;100

 

When initializing reference variable, it must receive address of other variable. To get address, use operator &. However, when variable is of same type, operator & is optional. It is also true with function arguments. When this optimization is undesirable, use operator +. Example:

 

int v = 5
int& r = &v ;;OK, r is initialized with address of v
int& r = v ;;OK, r is initialized with address of v
int& r = +v ;;r is initialized with value of v

Usage

Reference variable usage is easier (does not require *), but pointer variable is more flexible (can be used arrays, etc). Pointers and references are mostly used as function parameters. Caller passes address of a variable. Then function can modify that variable. This is often used with str, ARRAY and other variables to avoid copying of all data.

 

If a parameter is declared as byte pointer (byte* or !*), can be passed pointer of any type, or string. This is similar to void* in C++.

 

If expression that you assign to a pointer variable (or parameter, etc) has different type, QM may generate error. Use operator + to compile without error.

 

When using pointers, they always should point to an existing variable or other valid location in memory. Some functions also accept 0. Otherwise, macro will end with error message "Exception" or "Invalid pointer", or QM will exit or become unstable, or data will be corrupted. You should know life time of variables, because, when variable goes out of scope (is destroyed), pointer to it becomes invalid.