Mr. Martin's programming school

Variables

« Console programs Program flow »
In the previous example we printed the text 'Hello world!' on the console. When we run that program it will always print 'Hello world!' and never anything else. The text is fixed in the program, and we programmers likes to call that 'hardcoded' values. They can never change because they are compiled into the program. But if we want to have a program that could vary the text printed on the console, how would we go about to do that?

That's where variables enters the stage. They are called 'variables' because they can vary. How can they do that? They can, because they are stored in your computers work-memory, the RAM. Content in RAM can always be changed, unless somehow restricted, and in order to use this feature you will have to do two things:

  1. Tell the program where in memory to put your variable.
  2. Put something in your variable so that it contains something useful.

The first part is quite easy. Actually, the compiler and the linker will do that for you, but in order for you to be able to use it, you need to have some way of referencing it. That is equally easy: just give it a name. Doing this is called 'declaring' the variable. The syntax for doing that is:

    <name> <type>;

By using '<' and '>' I mean that you should type something of your own choice, in this case a name and a type. Then what is a type in this context? It is a piece of information to the compiler that tells it how it should use the variable. It could be for text, or maybe for integers. In the latter case the compiler can do arithmetics on the variable, but not if it is a text.

Text strings

Let us declare a variable for a text:

    String myText;

That's all. Very simple. Just do not forget the ';' at the end of the line. All C, C++ and C# instructions end with a ';'. That way you can split a long line into shorter lines and the compiler still knows when the instruction is completed. And how to put something into it? There are many ways. You can assign it a value in the code, but you can also use some function to do that, e.g. Console.ReadLine(); Console.ReadLine() will read what you type on your keyboard until you press enter or return. Then it will 'return' the result. You could use a line of code like this one to put the returned result into your variable:

    myText = Console.ReadLine();

You can try this by altering your program 'Hello', or by creating a new program. Try using this in your program:

    static void Main(string[] args)
    {
        String myText;
        Console.Write("Type something and then press return: ");
        myText = Console.ReadLine();
        Console.WriteLine("You typed: " + myText);
        Console.WriteLine("Press any key to terminate program...");
        Console.ReadKey();
    }

Note that the line is already in your code, so are the curly brackets and everything above. Also note that there are three more new things in the program snippet above:

Integers

Integers are for storing, well, integers, obviously. By that we mean that it stores numbers, not values that could have fractions. For values that can have fractions there are other types. Integers come in a few flavours using different numbers of bytes for storage. If you read Bits and bytes and stuff you will realize that one byte can store 256 different values. If we have an integer variable in one byte it could either contain a value between 0 and 255, or if signed, which is default, it can contain values from -128 to +127.

int A signed standard integer.
Int16 A signed two-byte integer.
Int32 A signed four-byte integer.
Int64 A signed eight-byte integer.
unsigned Int32 An unsigned four-byte integer.

The signed standard integer, 'int', normally uses the same amount of bytes as the architecture of the computer it runs on, i.e. 4 bytes on a 32-bit computer. This is just part of it. You can read more on MSDN, MicroSoft Developer Network, where you will find a lot of information.

Before we can start programming with integers we need to understand that Console.ReadLine() always returns a text string, i.e. a variable of the type 'String'. If you read 'The meaning of bytes' under Bits and bytes and stuff you will realize that the value returned is not suitable for calculations. E.g. the string '30' would contain two bytes with the values 51 and 48, or in hex: 0x3330, which will be 6552 in signed Int16. Not what we wanted.

Objects

Objects are like variables, but more. When we declare a String or an Int32 variable we do actually not only declare a space in memory for a value. There are so called 'intrinsic' types that only stores values, int is one of them, but most of them has been enhanced with the introduction of C#. If you look at the C/C++ reference for variables you will find a lot of simple variables. Some of then you can also use in C#, like 'int' and 'string' (with a lower-case 's').

So, what is so much better with objects? Well, they not only have space for a variable. They could have space for more than one variable, which we will see in the chapter 'Classes and objects', but what's more, they can contain functions! The object 'Console' contains functions of which you have already used three: WriteLine(), ReadLine() and Read(). You use the function either via the class name, e.g. 'Console', 'String' and 'Int32', or via the name of an object of that type, e.g. 'myText' from our samples above. Just type the class or variable name, a period and the function, just as we have done when we typed e.g. 'Console.GetLine()'.

Just for the record, we will talk more about functions in a later chapter. For now, since we are going to try variables of type Int32, we will take a quick look at two functions that can help us use Int32 variables in a console program, without knowing how functions really work.

Int32.Parse() Given a text with an integer this function will return an Int32 value.
Int32.ToString() This function will convert an integer into a string.

It is also possible to combine function calls. Rather than doing this:

    String stringValue;
    Int32 integerValue;
    stringValue = Console.ReadLine();
    integerValue = Int32.Parse(stringValue);

You could simply do this this:

    Int32 integerValue = Int32.Parse(Console.ReadLine());

This also demonstrates that a variable can be given a value when declaired.

Now, let's put this to practice. Alter your 'Hello' program, or create a new one, and enter this code:

    static void Main(string[] args)
    {
        Int32 a;
        Int32 b;
        Console.Write("Enter first value: ");
        a = Int32.Parse(Console.ReadLine());
        Console.Write("Enter second value: ");
        b = Int32.Parse(Console.ReadLine());
        Console.WriteLine(a.ToString() + " * " + b.ToString() + " = "+ (a * b).ToString());
        Console.WriteLine("Press any key to terminate program...");
        Console.ReadKey();
    }

Try it! But if you ever type something else than integers, the function Parse() will cause an exception. That is good, because it gives us a chance to handle errors. More about that in the chapter 'Error handling'. For now, hit F5 to run in debug mode, and try entering a text like 'hello' or 'four' rather than an integer number, and see what happens.



Pretty good information, don't you think? This type of error is called a 'run-time error' because it occurs when the program runs.

Floating point numbers

Fine, we have integers for pretty large numbers, positive as well as negative. But I see two things they lack. First of all, they are limited to a highest value. If that is not acceptable, we need another way to store numbers. The other thing is that they can not represent fractions. Ok, we will actually construct fraction from integers when we discuss classes later in this course, but even those cannot take any number.

A better way is to use some other way of storing values in the memory. For that reason we invented floating-point variables. In essence it is implemented as two signed numbers in the same 32 or 64 bit word. One of them is for the value as written with one digit plus some decimals, like 3.14154... for PI. The other one is for telling where the decimal point should be. When it comes to PI that would be an offset from the representation 3.14154... by zero, because the decimal point is already at the correct position.

For example the Avogadro constant, roughly 602214179000000000000000, an number that would not fit even in a 64-bit integer, can be represented by two values. Mathematicians would not write the number the way I did above, because it it really hard to count all digits. They would rather write '6.02214179 times 10^23' (10^23 = 10 raised to the power of 23). That means that the value is a little more than 6 multiplied 23 times by 10.

What we store in memory would then be two numbers: 602214 and 23, both positive. Hey! We lost precision! There were the digits 1, 7 and 9 after 602214, right? Yes, we lost precision. This is the best we can get in 4 bytes with one of the standard way of storing float values.

You really do not need to read all the details here, but you can skip down to the exercise if you find this boring.

If we store in 32 bits, that is four bytes, one byte is used for the exponent, 23 in this case, and the other three for the value, 602214 in this case:

    |0010010|00110000|01100110|00010111|
     \                         \        \________________________
      \                         \  
       \                         \ One byte for the exponent = 23
        \                         \______________________________
         \
          \                    Three bytes for the value = 602214
           \_____________________________________________________


Then why not use two more bits for the value? 6 bits is enough to represent 23. In that case the value could be 6022142, a little better. Yes, but then we would not be able to represent as large or small values. We trade maximum value for precision. That's the deal.

Today we use mainly two types for floating-point values; float and double:

Type Approximate range Precision
float ±1.5e−45 to ±3.4e38 7 digits
double ±5.0e−324 to ±1.7e308 15-16 digits


You can always check MSDN for information like this. The above can be found here unless Microsoft moved it since I wrote this. From that page you can also click your way to other datatypes and such.

Boolean

Sometimes it is not neccessary to store a value. The need might be just to have some variable that works as a switch, on/off, true/false etc. Those are called booleans. There was a mathematician by the name Bool that invented a math that implemented logics. It had a few strange qualities, but we will not go into those here. Enough to know that mr. Bool gave name to boolean variables. There are currently two types of booleans, and they can only have the value true or false:

bool The old type of boolean inherited from C/C++
Boolean The new, preferred, type of boolean for C#

You can use any of them in C#. A variable of type Boolean is normally used as a flag to remember a previous result for a later conditional test. We will read more about that under program flow. Here are two sample declarations:

    Boolean myFlag;
    Boolean myBoolean = false;

Constant expressions

Sometimes you need to use a constant expression. The first time you saw that was in the 'Hello' example. We printed a line 'Hello world!'. Maybe you notices that the text was in double quotes? That is how you declare a constant string expression. It is only used for variables of type String or string. If you need to use one char you use single quotes. Numbers, as you have seen, are declared with no quotes. Booleans are assigned by the reserved words True, true, False and false (remember, with C# we got new types spelled with first letter in upper-case). Here are some examples:

    Int32 myInteger = 5;
    Double myDouble = 5.0; // The fraction tells the compiler that the 5 is a float or Double.
    float myFloat = 3F; // The 'F' tells the compiler that the 5 is to be regarded the type float or Double.
    String myString = "Hello there!";
    char myChar = 'a';
    char myNewline = '\n'; // The '\' tells the compiler that this is a special character, a new-line.

We will encounter more of this later in the course.

Exercise

Now it's time for you to try your skills. What we have learned so far should be enough to solve this exercise.

  1. Create a new console program and name it 'Divide_and_conquer'.
  2. Declare three float variables. Use type Double to get conversions between float and string for free.
  3. Ask the user to enter two values, one at a time.
  4. Divide the first value with the second value and store the result in the third variable.
  5. Then print a result line like this: <first value> / <second value> = <result>
  6. Wait for the user to press a key to close the program.

This is how it may look when you run it:



If you would like to see a solution, check under code samples. Remember that there's always different ways to write a program, thus, your solution might differ from mine but still be correct. If you get compiler errors, try to understand them. If you cannot understand what it means, try Mr. Google. Just type the error message as search string, and see what you get.

Maybe you are ready now to take a look at program flow where the real programming logics starts?