FreeBasic Pointers tutorial
By VonGodric vongodric@hotmail.com


About this tutorial
This tutorial is meant to be as a guide to FreeBasi'c pointers world for beginners or who just wish some information about them and their support in FreeBasic. This tutorial will cover several types of pointers and their notations, also breafly about linked lists and their types and pointers to functions/subs. As well as pointers to pointers. Als should be noted that writing this tutorial I used fbc compiler 0.11 and becouse of that some of the stuff won't work on older versions!

What are pointers?
To understand what are pointers, we need to understand what variables are. Variables are references to a memory location in RAM where you can write or read data. So thus, they store some data and have an address in memory. In basic definition Pointers are variables that store address of another variable. That's where the name comes from Pointer -points to something.

Pointers in FreeBASIC
FreeBASIC unlike QBasic and many other BASIC dialects has full support for them. FB have them to following language structures:

The notation is very similar to C with exception of @ instead of & to take addresses. (for obvious reasons -it would conflict with { &h | &b | &o } numbering systems.) So let's get to it.

Starting with pointers...
here's our first small example:

When you run it -it will print out some strange number, further more, every time you run this program, it may show you different number, and it is most unlikely to get the same number after restart. When I ran it the number was: 4218880

This number is the memory address of the variable i. You can experiment with this a little -try different variable types for example. However be noted: that misusing pointers may lead to program crash, in worse situations even system crash!

Creating pointers is very similar to declaring a variable with dim: Dim name Type PTR|POINTER it doesn't matter do you use ptr or pointer, both are the same thing. so here's another litte example:

As you will see, both number are the same -however, You may notice that we pass the address of the variable i to the pointer ip. and ip used as is, is just a variable. You can also get the address of the pointer ip itself with @ip -and it will be different, because every variable has a unique address (it is possible to have variables with the same address however with Union's)

Now let's do some actual use of pointers:

The outcome will be 10 and 20 accordingly. The * will give the value of the variable that our pointer points to, or write to the value. Now you may have a question, what are they good for? Well great many things, pointers may speed-up or/and cut down your program in size. They'r most common use is however is in linked lists(will be looking at them shortly) and allocating memory from the heap (we'll discuss about that too). So here's one more example: As you see, pointers can be used just like any normal variables -you can assign values through them, use in calculations, pass as arguments, and mutch more. However word of caution: do NOT mistake *ip with just ip, one is a memory address -and therefore holds completely different value -and the other one the value of the variable the pointer points to. So therefore doing ip = ip * m for example will change the address it points to -and most probably will crash your program when you try to use it as pointer again: *ip = 100.

Pointers and arrays
Hopefully you understood previous stuff -if not try experimenting. Just as pointers may be used with variables, they can also be used with arrays. First a small example, then we'll analize it:

It will print out numbers from 0 to 10. So what is going on in there? We pass the address of the first array element to the pointer (ap=@array(0)), and then we go through the loop from 0 to 10 and print out. The notation *(ap + i) means: we will print out to what points the value that is in the parenthesis. You may however wonder why it prints out the right numbers? Shouldn't it screw the values -meaning that pointer always points to one byte in memory, but Integer is 4 byte? The FreeBasic compiler knows the size to what the pointer points, and meaning + 2 means actually to step 2 integer sizes forward.

Why is this useful: You may link what ever integer array (or of any other type you have specified) to one pointer and use it, without having to know exactly what is in it. Here is the same thing as above with a bit different notation:

Does the same thing -only difference now is instead of *(ap + i) ap[i] This is just a shorter notation and is a bit cleaner. In this case you don't need (in fact can't) use * in front of the pointer -that's because of the [ and ]. When these are used, compiler automatically knows that this is a pointer. ap[indx] = smth is also valid.

because of greater complexity of multidimensional arrays using pointers in FreeBasic, we'll skip them for now.

Pointers and UDT's
Like to arrays, you can have pointers to user defined types too. Here's for starter another example:

As you see, pointers with UDT's is very simle, first you define a ptr of the udt type and then take the address of it with @t and for getting the right field we use -> and field name. Note that * is not needed, because of -> what says already that this is a pointer. Assigning values through pointers is ptr->field = value. Like with arrays -different notations can be used: This second and third style, as you see is almost like array's with *(ptr+idx), infact, you can use pointers with arrays of UDT's too. And notation is almost same: As you see, all calculations are done for you, the index 3 will give the correct answer and you can choose from several styles and decide what suits you best.

Arrays/UDT's outside of DIM
When you use DIM -you use the memory that has been previously allocated for your running program by the OS (in FB the default is 1MB -however for more see the commandline options of fb), but what if you want more? One way to archive this would be to increase stack size allocated for your program -but if you want to have dynamically allocatable memory (games/programs often need that) -you are still stuck to that problem! Solution is to allocate memory from the system heap -let's just say that it's the rest of the free memory in your computer that is not already used by other applications. To use memory from the heap is more complex and dangerous then with DIM.

Why it's dangerous, is that this is often main source of crashes and errors, you probably have heard of memory leaks? Well you're about to get to know what they are: DIM procedure is controlled by the compiler -so whenever you allocate with it, it get's automatically deallocated once program exits SUB or FUNCTION for example. So memory is freed. However allocating memory from the heap, is not deallocated(freed) after your code has done it's work (exited sub/function or program itself) although modern OS's do free memory for you it is a good practice to not rely on it! Keep in mind a simple rule -once you allocate, next thing you do is make sure it get's deallocated!

Now what has this to do with pointers? Well everything, you get the address to the allocated memory block, so only using pointers can you acces to it. Now before we move on, let's make a simple example: Now let's analyse that. First we created an udt, then dimmed pointer to udt. then we allocated memory for our udt. ALLOCATE allocates memory from the heap. Len(mytype) returns the size in bytes that udt takes. We need to know how mutch memory to allocate. What allocate returns is a pointer to the first byte of the memory stream. And that's all, now we can use it almost like with Dim, but with exception of being able to access it only through pointers. The last thing is to deallocate -it erases(frees) the memory we had allocated.

  • Allocate - allocates memory, but does not clear previous content meaning you'll get all the garbage what is in that memory location. You can try the example above and read value of p->i before we assigned a value to it.
  • Callocate - Same as above, but also clears the memory. Meaning you'll get empty memory block willed with chr$(0).
  • Deallocate - deallocates memory.
  • Reallocate - Reallocates previously allocated memory to a new size. Does not delete the content.

    Warnings!

  • Always check that you wouldn't try to use and access NULL pointer. (Null pointer is a pointer that hasn't been initalised to point somewhere) -doing so may(and probably will) crash your program. If possible always check for the NULL ptr (if someptr<>0 then) it will slow down, but keep your program more stable.
  • It is possible that memory allocation fails (out of memory for example) - always check after allocating if it is not a NULL pointer.
  • Always make sure you deallocate memory you have allocated!
  • Make sure you never use previously deallocated memory.
  • When you allocate memory from the heap, make sure you absolutely NEVER write out of your allocation bounds. Stay in limits. because doing so, not only crash your program, but may crash your system also!
  • Use pointers and memory allocation only when you need to.
  • Use pointers and memory allocation only when you are sure you know what you are doing
  • Avoid pointer's spaghetti!

    Now that warnings have been said (reread them) we can move on and see how can we put an arrays to the heap.

    Notice that we allocated memory by multiplying the size of integer by ten, but true indexing ranges from 0 to 9, be aware of this! Placing UDT's to heap is done just the same way, only use len(udt) and if you want to have an array of it, multiply it by array size

    Linked lists
    Now that we have understood all previous, let's move on. As you saw pointers can point at UDT's, but they can also be a part of the UDT, furthermore pointer part of the UDT can point to it'own UDT -thus linked lists. All there is about these mysterious things is this that udt's point to other udt's. Let's start with simple example:

    This should be pretty easy concept to understand -node is one UDT block, that points to previous or/and next node or have NULL pointer meaning the end of the list. Why is this good for? Linked lists are in a way like arrays (you probably notices this by now) but they have several advantages and disadvantages over arrays.

    Pros
    Linked lists: Arrays:
    Each node is seperated unit Fast -since arrays are aligned in memory.
    Easy and fast to add/remove/replace nodes with one another Compact -takes less memory
    because each node is seperate unit -it doesn't take large memory block with the size of the whole List Lot Easier handling
    Same node can be pointed from different lists Are less bug prones
    Very dynamic Easy to copy/pass whole arrays (to a file)

    Cons
    Linked lists: Arrays:
    Consume more memory Slow and compilcated remove and insert
    Slower in most cases Consume big memory block (sometimes there's enough of free memory, but it is in too small chunks)
    Introduce many risks for bugs and memory leaks All pros's of the Linked lists
    more complex

    These tables should give you some ideas -there's certanly more no doubt but these should give you some idea. Although subject is interesting I will not however get really deep into linked lists here, because only on this subject there have been written entire books and there are many different types of linked lists in various shades and shapes. Some most common ones however:

    Pointers and functions/subs
    So far We've been through a lot and there's very little left to describe -although it is a matter on what could be possible to write heavy nooks. First We'll look at pointers in the functions/subs argument lists.

    Very similar actually to defining any other pointer -you just put a pointer, and pass the pointer or address with @.

    You may notice here byval argument -it is meant that pointer(value it holds) is passed by value itself and not reference(aka address) to that variable in what value is stored. Let's see here what byref does: Inside function/sub byref passed variable obtain the same address as of the variable that was passed. Functions can also return pointers, in that case you need to do function (args...) as type PTR.

    However more interesting part ( and very useful ) is pointers to subs/functions themselves. Yes, it is possible!. Here's small example:

    as you see, different sub's are called -and yes you can set default values on sub/functions pointers too. What is importand in sub/function declarations is that the prototype MUST match the prototype of the function/sub your are using pointers on. You can also pass function/sub pointers inside another function/sub parameter lists as well: As you see, using function pointers is almost same, only you must specify all types both the return one and also parameter list. Also as you can see, one pointers value can be given to another.

    Now look at this code -it should be pretty straightforward don't you think? Anyway declaring a pointer that points to another pointer must be declared explicitly as ptr ptr ... with the number of maximum redirections allowed. To point to the target you use * as many times as redirection is involved.

    Typeless Pointers
    Sometimes we do not really know or need to either, the type of the pointer in our program, let's say like when passing to the function/sub as an argument, we may be dealing with different types in it. For that in FB is ANY ptr. Here's example:

    As you see, nothing difficult here either. You may experiment with passing "wrong" numbers for wrong types. It should work except for strings. And that's more or less there is to typeless pointers. Also addresses can be passed without a problem from one pointer to another with different types -let's say from an integer ptr to the byte ptr. This way you can archive sort pointer casting from one type to another.

    Conclusion
    Well that's pretty mutch it for this tutorial. I hope you liked it and found something useful or new for yourself. One more thing however, throughout this tutorial I used @ symbol to obtain and address of smth, however these functions maybe used as well:

  • Procptr(sub/function name)
  • varptr(variable name)
  • StrPtr(string name)

    Also I want to thank lillo for reviewing this bag of grammatical bugs. And now farewell and thanks for reading this.
    VonGodric