Note: This tutorial is for absolute beginners. If you aren't an absolute beginner and you dislike the tutorial, that's too bad. If you are an absolute beginner and there's something you don't understand, read through the tutorial a second time. If you STILL have difficulties, e-mail me (TheMysteriousStrangerFromMars@yahoo.com) and I'll try to help you out. I do assume you at least have a decent knowledge of how to use your computer - if not, there's not much I can do for you. By the way, you'll need FreeBasic to use this tutorial - you download that at freebasic.net, so be sure to download and install it before doing this tutorial. Now start reading!
Last time we talked about the various ways to loop - that is, to do things more than once without typing the same line of code again and again. Today, as promised, we talk about different kinds of variables. I've told you that all variables are really just numbers inside the computer - but that when you use an HLL, you get to pretend they are different things. One of those things was the string, which acts like a bunch of characters instead of numbers, and then there are integers and floating point numbers, which just act like numbers. I'm going to tell you more about these variable types today.
The most basic variable type is the integer type. There are actually three kinds of integer variable: the Byte, the Short, and the Integer. All three are integers, but the Byte only has 8 bits, the Short has 16, and the Integer has 32. A bit is a single binary digit, a 1 or a 0, and every number in your computer is made out of bits. I'm going to give you a couple of simple formulae that you should remember if you can; you don't need to know how they work, you just need to know that they work. The first is
c = (2b), where b is the number of bits in a variable and c is the number of individual bit combinations possible by a variable with that many bitsWhat is this telling us? It's telling us how many unique data items can be represented by a variable with the given number of bits. For example, an 8-bit number (a Byte, that is) can hold 28, or 256, unique numbers: 1, 10, 11, 100, 101, 110, 111, 1000, 1001... etc. Now normally our integer variables are signed, meaning they can have negative or positive numbers. The formula to calculate the range of numbers a signed variable may hold is:
l = -0.5*(2b) u = 0.5*(2b)-1, where l is the lowest number, u is the highest, and b is the number of bits.That's how you figure that out... but what if you have a number that doesn't need to have negative values? Well you can make an Unsigned variable by putting a u in front of the name - so you have uByte, uShort, and uInteger. Now of course, the range here is different. In this case, l is always 0 and u is (2b)-1. Now in case you don't want to memorize all these formulas, it might be easier just to memorize the powers of two of the three types:
|Byte (8 bits)||Short (16 bits)||Integer (32 bits)|
|28 = 256||216 = 65536||232 = 4294967296|
Now you know about the different kinds of integer... what about floating point numbers? Floating point numbers are actually quite complicated and I won't try to explain to you just how they work. Suffice to say there are times when they will do things you won't expect and you should remember this is never a bug in the compiler, it's almost always a quirk of floating point arithmetic. I will give you a bit of a hint, but I won't describe or explain. If you remember scientific notation, floating point numbers work very much in a similar way (x * 10^n) except that the exponent is on 2 instead of 10 (since it's binary).
There are two kinds of floating point number: Single and Double. If you look in the FreeBasic manual you'll see the ranges of these. Now because of the way they are stored, floating point numbers can be very precise: that is, you can have the number 0.000000001, or something like that, and you have to admit that's pretty precise. You can also have extremely huge numbers, since all you have to do is change the exponent on the 2. This seems really great, but there is a "However" to the situation: floating point numbers are very precise, but there is a sacrifice of accuracy. That is, you can specify numbers very precisely, but when you do a mathematical calculation with them the result might not be perfectly correct. Yes, you can store 0.000000001 with great precision, but when for example you try to round 0.0099 to one decimal, you might not get 0.01! This may seem odd but it's just a fact of the way floating point numbers are stored, so you need to understand this.
As the name suggests, Double is more precise than Single. Of course, Double also takes up more memory. The floating point processor (a part of your CPU in your computer) does calculations with 80-bit floating point numbers internally, but in fact your Single is only 32 bits and your Double is 64. From the integer formulae you can easily figure out how many distinct values the Single or Double may hold... yes, it's a lot. However, the values they hold are not necessarily integer values, so the actual range of these is best found by looking in the FB manual ;) The floating point numbers may be manipulated and used in calculations just the same as regular numbers - with all the same operators like +, -, *, /, =, etc. You can also use them in conditionals and loops just the same.
Before we move on, I need to talk about Printing numbers on the screen. Normally if you ask FreeBasic to "Print a" where a is a number (and not a string) it will work just fine because FreeBasic will automatically convert a into a string which can be printed. However, if you want to print two things together, for example
This only works if a is a string. The reason is because "+" is used for two different things: with numbers, it's used to add the numbers together. With strings, it's used to put them together into one string. If a is a number in the above example, FreeBasic isn't sure what to do since there's a number and a string. There are two solutions. One of them is to do this:Print "Hello" + a
But the more correct method is to do this:Print "Hello "; a
Str() is something that converts a number into a string. I can't explain precisely how it works here (you will find out in tutorial #7!), just remember that's what you need to do to print strings and numbers together. You can also use the "&" operator to do the same thing, as inPrint "Hello " + Str(a)
And that will do the trick for you properly as well. Of course, if you do this:Print "Hello " & a
It will compile, but the number will be printed on a separate line from "Hello ". Of course, if you put a ";" at the end of the first Print line, then it will be fine. Print is kind of odd this way; it only prints things on the same line if you end with a ";". Anyways, now you know that, let's move on.Print "Hello " Print a
Next we come to the string variable type. Strings are, very simply, a bunch of characters. These can be letters, numbers, symbols, or anything else. Now in the early days it was enough to store a character using 8 bits. A 7-bit code called ASCII was developed for doing this, and of course if you use 8 bits to store it you may add 128 extra characters to the set (since each time you add 1 bit you double the amount of values it can hold). Normally, all strings are stored with ASCII even now, meaning each character in your string takes up 1 byte. However, in Windows a new 16-bit code called Unicode is sometimes used. Because it holds much more, it can hold all kinds of special characters, including many common Chinese and Japanese characters (of which there are millions). Unicode strings are treated specially by FreeBasic, so you'll have to look at the manual for information about those.
Most strings in FreeBasic are stored in one of two ways. There is the FB internal string format, which puts a few bytes of information in front of the string, such as what the length of the string is - after all, you need to know how long the string is or if you try to print it you'll print a bunch of other characters outside of the string on the screen! The other way is the method used in C, which is the ASCIIZ string. ASCIIZ strings don't have any bytes in the beginning of them - the first byte in such a string is the first character in the string. So how do you know where the string is? The last byte of the string is 0, or NULL. Hence the name ASCIIZ or simply "ZString" which is what you use to declare them in FreeBasic. Normally, though, you'd just use a regular string. Of course, if your string length is always the same you declare it with the "* n" where n is the number of characters the string will always have - we discussed that earlier. For many strings, however, the length is variable, meaning it can change. If you want to know the length of a string, use Len(thestring) where thestring is the name of the string you want to know the length of.
You might think those are the only kinds of variables... well, you would be wrong. Actually, all other variables are really just variations of the first kinds, though it's possible to create your own kind of variable based on the integer types (but then you'd have to write special code to interpret it specially, since it would not be a normal integer). The first special type of variable is the array. This allows you to create several of the same type of variable, all under the same name. For example, you might have a list of twenty names. Rather than creating twenty different strings, create a string array with twenty members:
Now if you want to access the first name, you would access it with names_list(1) - the second name is accessed with names_list(2), and so on. Each one is a separate string, but they all have the same name and you simply select the one you want with a number. This becomes very useful with loops, since you can use a loop to print all of the names on the screen:Dim As String names_list(20)
If you want to have a different number of items in your array, you must use ReDim:For i = 1 to 20 Print names_list(i) Next i
By the way, normally the first item in the array is 1, but you can make it something else. Another way of declaring an array is like this:Dim As Integer howmany, i ReDim As Integer myarray(1) Print "How many array items do you want?" Input howmany ReDim myarray(howmany) Print "Now there are " & howmany & " items in myarray." Sleep End
Where lb is the lowest member of the array and ub is the highest.Dim As Integer myarray(lb to ub)
One really fascinating possibility with arrays is that you can have more than one dimension. Take, as an example, the screen. Each row of the screen can be considered an array of colours (and colours are generally stored in integers, so it would be an array of integers with as many members as there are pixels across the screen), but what about up and down? You could represent your screen as a two-dimensional array, like this:
And then access the pixel at position x, y with myscreen(x, y). Of course, you can have even more than two dimensions, so arrays are very useful for many things. Also, if you remember matrices from math (if not, we'll be discussing them later... a lot later) - those can also be stored in a two-dimensional array.Dim As Integer myscreen(1024, 768)
Later we'll discuss pointers, which are often used similarly to arrays but are far more flexible. Right now, you aren't ready to learn about pointers so we'll go into the next item of business...
"User Defined Types" or UDTs. Generally, a UDT is simply a way to group several related variables under one structure. They aren't necessarily bitfields (the example I gave earlier) but just different variables grouped together. As an example, consider a ball moving around on the screen. You need several different numbers to keep track of the ball: the x and y coordinates of the ball, the velocity in the x and y direction, and perhaps some others such as the colour of the ball. Now you could declare each of these variables separately, but it's much more convenient to put them all together in a UDT - it becomes even less convenient to do it the other way if you have several balls bouncing around on the screen. What if you have a variable number of balls on the screen? You could create twenty x, y, velocity_x, and velocity_y components - or you could just create twenty variables of the type "object", after creating a UDT called "object" that has those components built in to it. Here's an example:
What did we just do there? We created an array of objects, with 10 of them to be exact. In fact, you don't have to do it like an array, you could also just create one of them - but the point is made, this is a very powerful way to group related variables together. But how would we access each variable individually? This is something very important, so remember this: you use the "." operator. For example, to access the x component of the object we created called one_ball, you use "one_ball.x". To access the colour component of the 5th ball, we use "ball(5).colour". Isn't that incredibly easy? Interestingly enough, it's possible to use UDT's inside of other UDTs, like this:Type object As Single x, y As Single vx, vy As Integer colour End Type Dim As object ball(10) Dim As object one_ball
Then you access them with one_ball.position.x or one_ball.velocity.x - or ball(5).position.x, or anything else, depending on what's declared and how.Type vector As Single x As Single y End Type Type object As vector position As vector velocity As Integer colour End Type Dim As object ball(10) Dim As object one_ball
I won't give you the bouncing ball example today, because you don't know how to do graphics yet, but I will give a simple example of a list of people:
Whoa! This is probably the longest program you've seen! But I promise you there isn't a single thing in here you haven't learned about yet - there are conditionals, strings, numbers, arrays, UDTs, loops, input and output - we even change the strings around, and there are both variable-length and static strings. Furthermore, we have a variable-sized array! This is one heck of a complicated program, but everything there is something you understand, or should understand. If not, read through it, run it a few times, try it out - figure out what everything is supposed to do. You can add comments to it if it helps you understand everything. Figure out what it does and how it works (tip: if you run it, don't put too many people in your company or you'll be typing information about people all day!) Once you know how it works, you'll be surprised at how simple it really is. (In perspective, this program only has 56 lines. Did you ever stop to realize that the FreeBasic compiler is itself a program? The FreeBasic compiler has some 200,000 lines - that's right, two hundred THOUSAND. Turns out this program ain't so complicated after all!)Type person first_name As String last_name As String middle_initial As String * 1 age As Integer dob As String * 10 End Type Dim As Integer npeople, i ReDim As person my_people(1) Dim tstr1 As String, tstr2 As String, tstr3 As String Print "How many people are in the company?" Input npeople ReDim my_people(npeople) For i = 1 to npeople Print "Person #" & i Print "First name?" Input my_people(i).first_name Print "Middle initial?" Input my_people(i).middle_initial Print "Last name?" Input my_people(i).last_name Print "Age?" Input my_people(i).age Print "Birth month?" Input tstr1 Print "Birth date?" Input tstr2 Print "Birth year?" Input tstr3 'Add a 0 to the month or day if either is less than 10 If Len(tstr1) = 1 Then tstr1 = "0" + tstr1 If Len(tstr2) = 1 Then tstr2 = "0" + tstr1 my_people(i).dob = tstr1 + "/" + tstr2 + "/" + tstr3 Next i Do Print "Which employee ID number would you like to see? Press 0 to exit." Input i If i = 0 Then Print "Press any key to exit..." Sleep Cls End Else Print "Name: " + my_people(i).first_name + " " + my_people(i).middle_initial + ". " + my_people(i).last_name Print "Age: " & my_people(i).age Print "DOB: " + my_people(i).dob Print "" End If 'This is an infinity loop! However, there is a way to break out, if you enter 0. Loop
Whoa. I'll say it again, not because I'm really amazed about anything but because you just waded through 56 lines of code and you understand it all (in other words, you're the one who should be amazed)! (Incidentally, if you don't, go read through it again a few times. If you have to, look over all the past tutorials as well. It uses concepts learned in ALL the tutorials, so it might be worth looking through them again a few times to figure it out.)
So what's the assignment for today? The assignment for today is to write a program that lets you enter recipes. Each recipe has a name which may be no more than 30 characters long, a string describing the ingredients, and a string describing the instructions for making the recipe. Tip: to make a string appear on more than one line when you print it, use the following bit of code:
This works because Chr(13) returns a string which is equivalent to a newline character.somestring = "something here" + Chr(13) + "this appears on the next line"
Note: This was edited because I made a bit of a boo-boo: you can't put variable-sized arrays inside Types, so it would be impossible to implement a recipe with more than on ingredient where the ingredients are an array of UDTs. Sorry about that! Later you'll learn of pointers, with which it is possible to do this, but until then you'll just have to do it with strings. Another possibility is that you could use a fixed length array and ignore any elements that aren't used. The example here uses that, and if you don't feel like trying to write the program yourself, you can look at the example instead (it's only 20k, so it shouldn't take long to download even on a slow connection).
Whether you do the assignment or not, tutorial 5 will be coming pretty soon... we'll discuss procedural programming and modularization, and specifically how these things work in FreeBasic. Until then... enjoy yourself!
The fifth tutorial is here(<--Previous) Back to Index (Next-->)