Hopefully, you had some fun last month reading “Beginning C#: Basic I/O and Variables,” in which you created coloured text and got the computer to ask you questions.
This month, we’re going to dig into variables a little deeper.
Last month, I introduced you to the very basic concepts of what a variable is, and what its purpose in the scheme of things is. Variables, if you recall, hold your application’s data.
Everything you do, process, or handle in any way, in any application you write, needs to be stored in variables. Variables are named slots that point to a value of some kind stored in your application’s memory and can hold a staggering number of different things.
Up until now, you’ve seen three very basic types:
- int
- bool
- string
These three types are known as primitive types because they are very simple in construction and usage and very simple to understand and work with.
Behind the scenes, even these three basic types have complexity beyond what I’m describing here, but you can safely not worry about that for now.
There are other primitive types, too. These are:
- byte
- char
- decimal
- double
- float
- long
- short
There are also some variations on these types that allow you to be very specific about the type of data these use, such as restricting to only positive numbers. For now, let’s take a look at the basic types.
Byte, decimal, double, float, long, and short are all different types of numbers. An int, which you’ve already looked at, can hold only whole integer numbers such as 1, 2, or 100.
A byte can only hold an integer number no larger than 8 bits in length (a little more on that in just a moment). Decimal, double, and float hold fractional and high precision numbers with differing amounts of precision.
Char holds a single ‘character’ such as ‘A’, ‘B’ or ‘1’, ‘2’ and is typically one element from a string.
Finally, long & short are “shortcuts” to different “bit sizes” of integers.
What’s in a Bit Size?
I’m not going to go into a whole tutorial on this (I’ve already posted in this column previously about the subject: https://www.codeguru.com/news/bit-twiddling/) but a quick recap is in order, so you understand the context of what I’m showing you.
When we say something has a given number of bits, we mean it has a certain width, and the limits on that width impose how large or small of a number the variable can hold.
Without getting too technical, 1 bit is equal to one wire carrying electricity inside your computer. By putting these wires into bundles and assigning different multiples of 2 to each wire, your computer is able to count. The number of these wires that are in a bundle are called the bit size, and the bit size determines the maximum number that can be counted.
If we look back at our primitives, starting with a byte, a byte is a fixed “8 bit number”. That is, it has only 8 wires. If you start at 1, then go to the left, adding wires and multiplying by 2 each time, until you reach 8 wires, you’ll get the following numbers:
1, 2, 4, 8, 16, 32, 64, 128
If you add all these numbers together, you’ll get a total of
1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 = 255
This means that ‘255’ is the highest number that an 8 bit byte can hold, so a byte can hold a value from 0 to 255.
A char is also typically 8 bits because most letters in the computer’s default alphabet fit into the same number range. For example, the letter ‘A’ is assigned code 65, ‘B’ = 66, ‘C’ = 67, and so on. In today’s modern world, however, a char can usually represent up to 16 bits, allowing it to represent a single character from an extended character set such as Unicode.
A decimal allows you to hold numbers with decimal places. For example:
1.23 or 567.890123
How the number of bits gets worked out for a decimal is way too complex for this intro text, but, just like bytes, they do have an upper limit. It’s for this very reason that a 64-bit computer is more powerful than a 32-bit computer, simply because a 64-bit system can handle larger amounts of data and numbers.
Doubles and floats, like decimals, are designed to handle fractional numbers, but with different levels of accuracy.
For most calculations you would do involving fractional numbers in C#, you would use decimal, because the answers you get from mathematical operations will give you the most accurate result. Inaccuracies, even small ones, when dealing with financial data, for example, could cause a lot of problems. Decimal values are designed to avoid such errors. Floats and doubles are better designed for scientific data, where small rounding errors in the accuracy of the numbers you’re working with won’t cause too much of a problem, and where a small amount of inaccuracy is acceptable for a faster result.
Finally, long & short are aliases for different sizes of integer.
In the C# base library, when you use an ‘int’, you’re usually (even on a 64-bit machine) going to be using an ‘Int32’ which, as the name suggests, is an integer that’s 32 bits in length.
A ‘short’ is usually used to represent an ‘Int16’ and a ‘long’ is usually used to represent an ‘Int64’.
Once you start to understand the different types of variables and what they can hold, you can start to do basic “Math operations” on them. For example, if you do the following:
int valueOne = 10; int valueTwo = 10; int theResult = valueOne + valueTwo;
The variable holding ‘theResult’ will be equal to 20 (10 + 10 = 20). You could also do things like
int theResult = 1 + 1;
and initialize your variables directly with a math equation.
All the basic math operations are supported:
- + for addition
- – for subtraction
- * for multiplication
- / for division
There are others, too, but for now we’ll keep it simple. Some variable types still support math operations, but instead of solving the equation, you end up “Joining things.” Try the following on two strings:
String hello = "Hello"; String world = "World"; String result = hello + " " + world; Console.WriteLine(result);
The result should be “Hello World”.
Collecting Things Together
The last thing I want to mention before I wrap this month’s post up is how to “collect” related values together.
One last concept where variables are concerned is the concept of an “Array.” Put simply, an array is a way to combine a set of related variables into one named place. For example, the names of the people in your family might look like the following in three string variables:
string father = "John Smith"; string mother = "Mary Smith"; string childOne = "David Smith"; string childTwo = "Jenny Smith";
For certain types of application, this becomes very difficult to work with, because you have to keep duplicating code for different variables. Instead,, what you can do is collect them together in numbered slots in an array as follows:
string[] myFamily = new string[] {"John Smith", "Mary Smith", "David Smith", "Jenny Smith"};
You then can access the separate parts of the collection by using a numbered offset as follows:
Console.WriteLine("My Father is : {0}", myFamily[0]); Console.WriteLine("My Mother is : {0}", myFamily[1]);
If you then have an ‘int’ variable acting as a counter, you can use that counter to select the data item you want to process, as follows:
int myIndex = 0; Console.WriteLine("My Father is : {0}", myFamily[myIndex]); myIndex = 1; Console.WriteLine("My Mother is : {0}", myFamily[myIndex]);
This, as you’ll see when we start looking at loops and repetition in C#, can become very useful indeed. To specify that something is an array, you simply use the primitive type we’ve already looked at, and follow it with a double square braces []
The two things to remember with arrays is that you must ‘new’ them before you use them, and they ALWAYS start counting from 0, not from 1.
If you know your array is never going to have more than 4 slots (0 to 3), you can allocate it as follows:
int myNumbers[] = new int[4];
Allowing you to then use it like so
myNumbers[0] = 1; myNumbers[1] = 10; myNumbers[2] = 100; myNumbers[3] = 1000;
If, however, you try
myNumbers[4] = 10000;
You’ll get an error, because you didn’t allocate enough slots to store a 5th variable.
As you saw earlier, you also can create an array and add items to it at creation time, C# will work out how many slots you need and create the right number.
int myNumbers[] = new int[] { 1, 10, 100, 1000 };
Will have the same effect as the four lines above.
We’ll get back to some more in-depth code next month. For now, however, use the examples in the previous posts, practice using different types of variables and values, as well as collect them into arrays, and perform some maths on them.
Next month, we’ll be looking at decisions and how to make your program choose different things depending on the data it’s been given and start showing you how to make your programs a little smarter.