Introduction to Pointers

Written by rdc

What is a Pointer?

A pointer is a 4-byte data type (on 32bit systems) or 8-byte data type (on 
64bit systems) that holds an address to a memory location. A pointer 
doesn't contain data, it points to data once it has been initialized. An 
uninitialized pointer points to nothing and is undefined.

To understand pointers, think of an egg carton that has numbers 1 through 
12 printed on the bottom of each "hole" (where you put the eggs). These 
holes are like memory locations in a computer; each hole, or memory 
location, has an address, in this example, 1 through 12. If an egg 
represents a data item, then an egg in hole 1 has an address of 1.

Normally, you would access the data directly through the use of variables. 
When you DIMension a variable of a particular type, you are setting aside 
storage space for the data. You do not need to know, or care, where the 
data resides since you can access the data directly through the variable. 
This is like reaching out and picking up the egg in hole 1 (reading the 
data) or putting an egg in hole 1 (setting the data) without looking at the 
numbers written on the bottom of the hole.

Using pointers is a bit different. Imagine you have a little scrap of paper 
that will represent our pointer. Right now it is blank and doesn't point to 
anything. This undefined pointer can't be used until it is initialized. To 
initialize the pointer, write a 1 on it. Now our pointer is "pointing" to 
hole 1 in our egg carton. To put data (an egg) in hole 1, we look at our 
scrap of paper, match it to hole 1 and place the egg in the hole. To 
retrieve the egg we do just the opposite. We match our slip of paper to 
hole 1 and then grab the egg. All the putting and getting of the egg has to 
be done through the slip of paper and is called dereferencing the pointer. 
That is, we get to the data through the referring address contained in the 
pointer, the number 1. The pointer doesn't contain the data; it contains a 
referring address to the data.

In FreeBASIC we define a pointer using the Dim and Ptr statements:

   Dim aptr As Integer Ptr

This statement corresponds to our blank piece of paper in the above 
example. The pointer doesn't point to anything and is undefined. If we 
tried to use the pointer right now, more than likely the program would 
crash.

In order for a pointer to be useful, it must be initialized:

   Dim aptr As Integer Ptr

   aptr = Allocate(SizeOf(Integer))

Here we are using Allocate to set aside enough space in memory for an 
Integer and loading the address of that space into aptr. The SizeOf macro 
returns the size in bytes of the passed data type. You could use len 
instead of SizeOf (since .13b) if you prefer.

Once we have initialized the pointer, we can now use it:

   *aptr = 5
   Print "aptr: "; *aptr

Notice the * prefix on aptr. The * is the dereference operator. This is 
like matching the number on the slip of paper to the number on the hole in 
the egg carton. By using the * operator, we are able to get at the data 
(egg) contained in the hole pointed at by aptr.

Here is a complete example program:

   Dim aptr As Integer Ptr

   aptr = Allocate(SizeOf(Integer))
   *aptr = 5
   Print "aptr: "; *aptr
   Deallocate aptr
   Sleep

The Deallocate function frees the memory pointed at by aptr, and makes aptr 
undefined once again. This is like erasing the number on our slip of paper. 
If we were to use aptr after deallocating it, the program would crash.

What Good are Pointers?

A major reason for adding pointers to FreeBASIC is that many external 
libraries require pointers to type structures and pointers to strings. For 
example, the Win32 API has many structures that must be filled out and then 
passed to a function through a pointer.

Another use of a pointer is in a Type definition. Type defs in FreeBASIC 
can only contain fixed length strings, but what if you don't know the 
length of a string until the program is running? A pointer can serve this 
purpose.

(It should be stated that the Type definitions can now support variable 
length strings.)

   Type mytptr
      sptr As ZString Ptr
   End Type
   'This function will allocate space for the passed string
   'and load it into a memory location, returning the
   'pointer to the string.
   Declare Function pSetString(ByVal s As String) As ZString Ptr

   'type var
   Dim mytype As mytptr

   'Set a variable string into the type def
   mytype.sptr = pSetString("Hello World From FreeBASIC!")
   Print "aptr: "; *mytype.sptr
   Deallocate(mytype.sptr)
   Sleep
   End

   Function pSetString(ByVal s As String) As ZString Ptr
      Dim sz As ZString Ptr
      
      'allocate some space + 1 for the chr(0)
      sz = Allocate(Len(s) + 1)
      'load the string into the memory location
      *sz = s
      'return the pointer
      Return sz
   End Function

Here we define our type with a field sptr as ZString Ptr. Zstrings are null 
terminated strings and are used by many external libraries and are designed 
for dynamic allocations. Once we define our type we create an instance of 
it with the Dim statement:

   Dim mytype As mytptr

We then call our function pSetString to get the address of the variable 
length string we want in our Type def.

   mytype.sptr = pSetString("Hello World From FreeBASIC!")

Remember sptr is defined as a pointer, not a string variable, so pSetString 
is returning a pointer (memory address) to the string not the string 
itself. In other words, if the string is in hole #1, pSetString returns 1.

The function pSetString uses a temporary ZString sz, to Allocate space for 
the passed string parameter s. Because a ZString is a null terminated 
string, we must add 1 to the length of s for the null terminator in the 
Allocate function.

   'allocate some space + 1 for the chr(0)
   sz = Allocate(Len(s) + 1)

Once we have allocated space for the string, we use the dereference 
operator * to load the data into the memory location.

   'load the string into the memory location
   *sz = s

We then return a pointer (the address of the string) back to our type, 
which is saved in mytype.sptr.

   'return the pointer
   Return sz

We can now dereference the string in our type using the dereference 
operator.

   Print "aptr: "; *mytype.sptr

Pointers can be confusing for the uninitiated, however they need not be if 
it is kept in mind that the pointer doesn't contain data, it simply points 
to some data. The pointer is a memory address, and you manipulate that data 
through the dereference operator *. It really isn't much different than a 
normal variable.

Last reviewed by sancho3 on February 07, 2018