> # Pointers in FreeBASIC written by Eclipzer ### Introduction to Pointers One of the newest additions to the BASIC language (FreeBASIC) is pointers. Though powerful, programming with pointers is not a simple task. Pointers require a whole new level of understanding to be used effectively. Regardless of your programming experience, if you've never worked with pointers before, it's going to take some time to wrap your head around them. ### What's a Pointer? A Trip Down Memory Lane So what exactly is a pointer?! For simplicity, a pointer can be thought of as a variable, with the exception that, instead of holding data, it points to the data by holding the memory address of that data. Every piece of memory has a unique number associated with it. These numbers are refered to as memory addresses. Information can be stored at these addresses to be used at a later point in time. The key thing to understand is that, unlike a variable, where you only have access to the value of that variable, with a pointer you actually have access to where a value is stored in memory. ### Creating a Pointer You define a pointer exactly the same way you do a variable. The only difference is that you add POINTER or PTR to the end of your statement. Also a pointer's type must be excplicitly stated in its definition.
>       dim myPtr     as integer ptr     'use ptr suffix to define pointer
>       dim myPointer as integer pointer 'use pointer suffix to define pointer
> It is important to understand that, unlike variables, a pointer's type does not affect the amount of memory it uses. This is because memory addresses are all the same size, and a pointer simply holds a memory address. Let's take a look:
>       dim myByte as byte    'define byte
>       dim myWord as integer 'define integer

>       print len(myByte) 'output size of byte (in bytes)
>       print len(myWord) 'output size of integer (in bytes)
> In the above code, the size of a byte is in fact one byte, while the size of an integer is four bytes, exactly as we'd expect. Now for the pointers:
>       dim bytePtr as byte    ptr 'define byte pointer
>       dim wordPtr as integer ptr 'define integer pointer

>       print len(bytePtr) 'output size of byte pointer (in bytes)
>       print len(wordPtr) 'output size of integer pointer (in bytes)
> It might be a little unexpected, but these two pointers are exactly the same size, even though one is a byte pointer and the other an integer pointer. So to reiterate, pointers hold memory addresses, which are all the same size, hence pointers always use the same amount of space, regardless of their type. This naturally begs the question, why must we explicitly state a pointer's type if it doesn't affect the space allocated to it? What exactly does the pointer's type do or mean? We'll tackle this soon, but first we need to understand a few more things. ### Pointer Operators In all honesty, a memory address doesn't do much for us in programming. It's when we can get a hold of the address of something specific in memory that pointers start to make a little more sense. To this end we introduce two new operators: the "address of" operator and the "contents of" operator. The "address of" operator is denoted with the '@' symbol and is used to obtain a variable's memory address. The "contents of" operator is denoted with the '*' symbol and is used to obtain the contents of a pointer.
>       dim myVar as integer     'define integer
>       dim myPtr as integer ptr 'define integer pointer

>       myVar = 512    'assign myVar a value
>       myPtr = @myVar 'obtain the memory address of myVar

>       print myVar  'print myVar
>       print @myVar 'print address of myVar

>       print *myPtr 'print contents of myPtr (myVar)
>       print myPtr  'print myPtr (address of myVar)
> Notice that the output is identical. The first two lines are in terms of myVar, while the next two lines are in terms of myPtr. Let's review the two most important lines in the above code.
>       myPtr = @myVar
> Remember myPtr is a pointer, meaning it holds a memory address. So, anything we assign myPtr must also be a memory address. We use the '@' symbol to obtain the memory address of myVar and then assign it to myPtr. So looking at the above line of code you should literally read "My pointer equals the address of my variable".
>       print *myPtr
> Here we're displaying the contents of myPtr. Because we've set myPtr to point to myVar when we display the contents of myPtr we're really displaying myVar. It is important to understand that pointers only point to data, they do not contain it. Therefore if the data changes the contents of the pointer change as well.
>       dim myVar as integer
>       dim myPtr as integer ptr

>       myVar = 512    'assign myVar
>       myPtr = @myVar 'point to it

>       print " var =";myVar  'output myVar
>       print "*ptr =";*myPtr 'output contents of myPtr (myVar)
>       print " ptr = ";myPtr 'output myPtr (address of myVar)
>       print

>       myVar = 256 'change the value of myVar, indirectly changing the contents of myPtr

>       print " var =";myVar  'output myVar
>       print "*ptr =";*myPtr 'output contents of myPtr (myVar)
>       print " ptr = ";myPtr 'output myPtr (address of myVar)
>       print
> Here, by simply changing the value of myVar we have indirectly changed the output of *myPtr. It is important to note that the value of myPtr remained unchanged, as it still contains the address of myVar. Well, if we can change the contents of myPtr just by changing the value of myVar, can we do the opposite? Change the value of myVar by simply changing the contents of myPtr? As it turns out, we can do this rather easily. We simply change the following line from the above code:
>       myVar = 256  'change the value of myVar, indirectly changing the contents of myPtr
> to:
>       *myPtr = 256 'change the contents of myPtr, indirectly changing the value of myVar
> As you can begin to see, this is where pointers derive a lot of their power, in the ability to change data indirectly without having to actually "contain" the data. They only need to "point" to it. ### Pointer Arithmetic The idea behind pointer arithmetic is that we can use a pointer as a starting point and then add or subtract from that pointer to access a new memory location. The syntax for this can be written one of two ways:
>       myPtr[offset]
> or:
>       *(myPtr+offset)
> In both instances, we are dealing with the value stored at the offset from myPtr. Now, you may be asking how big (in memory) is an offset. If we have the following:
>       value = *(myPtr+10)
> are we talking 10bits from myPtr or 10bytes or 10 something else all together? Remember how we had to explicitly state a pointer's type when we defined it? This is where that comes into play. A pointer's type affects how many units of memory we move for each offset value.
>       dim myVar as integer     'create an integer in memory
>       dim myPtr as integer ptr 'define pointer

>       myPtr = @myVar 'point to our integer

>       print *(myPtr+10) 'output 10th integer from myPtr
>       print myPtr[10]   'same as above, using different syntax
> Since our pointer is an integer pointer, we're moving 10 integers (40bytes) from myPtr to output whatever value is at that memory location. This brings up a VERY important point. Because we're using an offset from a pointer to access a new memory location, we must be certain to know what our new address is pointing at. If you start writing to memory that you havn't explicity allocated, it's almost guaranteed that you will crash your program. Hence, the preceeding code is poorly written, because even though our pointer points to myVar, the offset points to 10 integers away from myVar. Since we havn't explicitly allocated this memory, there is no way to be certain what it is we are pointing at. A better example would be:
>       dim myVar(10) as integer     'create 11 integers (0-10) in memory
>       dim myPtr     as integer ptr 'define pointer

>       myPtr = @myVar(5) 'point to 5th integer

>       myPtr[-1]=10  'set integer 5-1 (4) to 10
>       *(myPtr+1)=20 'set integer 5+1 (6) to 20

>       for i=0 to 10
>         print "integer"+str$(i)+" =";myVar(i)
>       next
> In this instance, by creating an array of integers, which are laid out consecutively in memory, we can safely use pointer arithmetic to access the other integers in the array. Notice, however, that myPtr doesn't point to the begining of the array, it points to the 5th integer. To address integers 0 to 4, we use a negative offset. A positive offset is used to address integers 6 to 10. ### UDT Pointers Pointers aren't limited to just the standard FreeBASIC data types. You can also define a pointer to point to a UDT (User Defined Type). To do this you simply use the name of the UDT for the type in the pointer definition.
>       type myUDT
>         var1 as integer
>         var2 as integer
>         var3 as integer
>       end type

>       dim myType as myUDT     'create UDT in memory
>       dim myPtr  as myUDT ptr 'create a pointer of type myUDT

>       myPtr = @myType 'point to our UDT
> Remember the pointer type just indicates how much memory the pointer can address at one time. So, we must first create our UDT in memory and then have our pointer point to it, before we can start using the pointer. Now that we have a pointer to our UDT, how do we access it's elements through the pointer? Your first thought might be to use the standard dot notation.
>       myPtr.var1 = value 'assign value to var1 using myPtr???
> However, this is incorrect. The dot notation is only used for variables, not pointers. With a pointer we need to use the "->" symbol.
>       myPtr->var1 = value 'correct pointer notation to assign value to var1
> It might seem odd, at first, to have two different symbols ("." and "->") which essentially do the same thing. With two symbols, though, we can quickly determine how we are accessing our information. The "->" symbol tells us immediately that we're working with a pointer. Otherwise we're working directly with a variable. ### UDT Array Pointers What happens if we have an array of a UDT?
>       type myUDT
>         var1 as integer
>         var2 as integer
>         var3 as integer
>       end type

>       dim myType(10) as myUDT     'create 11 UDTs (0-10) in memory
>       dim myPtr      as myUDT ptr 'create a pointer of type myUDT

>       myPtr = @myType(0) 'point to first UDT
> How do we access the UDT elements for a given array element? If we follow what we know, we might assume:
>       myPtr[offset]->var1 = value 'assign value to var1 of array element offset through myPtr???
> However, in this case we use a "." instead of the standard "->" symbol.
>       myPtr[offset].var1 = value 'correct pointer notation to assign value to var1 of array element offset
> We can do this because the brackets indicate that we're working with a pointer. If we were working directly with the array we would use parenthesis instead. It's important to note that the brackets aren't needed if we're already pointing to the array element we want to modify.
>       myPtr = @myType(0)    'point to element 0
>       myPtr[5].var1 = value 'assign value to var1 of 5th element

>       myPtr = @myType(5)    'point to element 5
>       myPtr->var1 = value   'assign value to var1 of 5th element
> Both of these code blocks produce the same result. ### Conclusion As you can see, pointers introduce a whole new way of programming. Though this introduction should give you enough information to start using pointers on your own, there are still many advanced techniques to be learned. But that is for another article. Hopefully, you've enjoyed this article. Until next time! -Eclipzer ### Review The following is a quick review of the material covered in this article. Think of it as a reference sheet. Define a pointer using either the POINTER or PTR keyword.
>       dim myPtr     as myType ptr
>       dim myPointer as myType pointer
> Use the '@' and "*" operators to obtain the address of a variable or the contents of a pointer.
>       myPtr = @myVar 'obtain address of variable using '@' operator
>       myVar = *myPtr 'obtain contents of pointer using '*' operator
> Use pointer arithmetic to obtain the contents of a memory location from a pointer.
>       value = myPtr[offset]   'obtain contents at offset from myPtr (array style)
>       value = *(myPtr+offset) 'obtain contents at offset from myPtr (pointer style)
> Use the "->" symbol to access the elements of a UDT (user-defined type) with a pointer.
>       value = myPtr->element   'access UDT element using the "->" symbol
> Use brackets with dot notation (".") to access UDT elements of an array.
>       value = myPtr[offset].element   'access UDT element of an array