Jump to content

C++ Programming/Variables & Intro to Control Statements for C++

From IdeaWazaWiki

Variables & Intro to Control Statements for C++


Scope of this Chapter


In this chapter you will write your second program for C++. It will help you learn about variables. It will cover what they do and help you decide what you need in order to use them. This chapter will use control loops but will not explain them in depth, because that is the job for the next chapter; and we would not want to confuse you. This chapter will also use variables, but not fully explain what their types mean; this will wait for the arithmetic chapter.

You will have to know how to use your specific compiler. Check the appendixes for more information.

The program you will be written using standard C++ libraries, but many compilers tend to not follow the standard a hundred percent, so there will be a supplement attached to the bottom of this chapter that explains what to do when you run into problems with specific compilers.

Let's Program


The first thing we want to do with any program is to write the "main" entry point.

int main()
{
   //Program always starts here
   return 0;
}

main() is basically what the system calls when you start the program. It should always have the type integer (int), and barring error should always return 0. Some IDE's (the thing you write your code in) are set up so they can tell you the return value. You can take advantage of that to help you in debugging your program.

Variables


Variables are pieces of information that can vary from time to time (ie they are changeable). All of your non-variable code exists solely to manipulate variables. The sooner you realize this, the better a coder you will become. One thing this means, is that you should typically, knowing that not everything can be foreseen, define your variables first, then starting writing your code.

In order to know what variables you will need, you have to know what you need to do, ie know your program. We are going to program a text graphics game called Pitfall. Its a game were you fall through a pit and maneuver around trying to avoid hitting the rock walls around you. When you brutally smash into the side of the wall, you are dead, and the game is over.

So we know that in our program that we are going to have a person and a pit. We also know, from our past experiences, that any program that runs in real time, ie does not wait for user input, and does not perform a hidden data process and quit (ie a compiler), needs a function to keep track of time. With a timer, the program can be kept under control so it does not perform calculations at millions of times the rate that the user can think at.

So now we know that we are going to need variables for a person, a pit, and a timer.

We are going to need to know what our person looks like. We have decided1 to represent a person with a single character, the 'Y'. It looks kind of like a person with their arms sticking out into the air.

char person = 'Y';

Now, you are probably already thinking, why not just when it comes to displaying the person on the screen, just tell it to print the 'Y' directly! It would be the easier way to do it, but it would make the program harder to change later on. What if you decided you wanted it to be a 'X' instead, thinking that it looks more like a person since it has arms and legs. This way you can just change one variable, and not hunt down all the commands that use it. And if you really want to enforce this fact, and its good idea to do so, you define it as:

const char Person = 'Y';      //capitalizing can be used to differentiate constants from regular variables

This means that the character is a constant! Ie, a non varying variable. It really isn't constant. You could change it while the program is executing through assembly if you really felt the need, but the const just tells C++ to not let you change it (this makes it harder to make mistakes). If you find out later that you need to change it during runtime, then you can just remove the const from out in front of it.

We also need to know where our person is at. We are going to give him a x and a y position. Our person's x position refers to his horizontal (-) position across the screen. Our person's y position refers to his vertical (|) position on the screen.

int personX = 39;
int personY = 5;

An astute reader would have noticed that it seems I have added some numbers to our declarations. These numbers specify the starting position of our person. In a standard graphical text mode, which we will not be changing since different compilers have different, or no method at all, for doing this, there are 80 characters horizontally and 25 characters vertically (80x25). 39 characters from the left is right in the middle of the screen. You might say 40 is the middle, but remember chapter 0, computers count from 0, not 1 (so subtract 1). 5 characters is just a little down from the top of the screen. We want to keep our person up high so the rocky walls can be more easily avoided (look ahead), but not too far up because it looks bad.

Now we can move to defining our pit. Our pit is just going to be a tunnel. Since it is always a good idea to use as little variables as possible to conserve ram, a little ridiculous here, but nevertheless a good programming trait, we are just going to define variables for both sides of the pit (if you are clue less right now why this is, then use your imagination to picture a cross-section of a giant pit). We are going do draw the pit so it extends from the top of the screen down to line number 20; because of this we need to define it as an array.

int start[20];
int end[20];

An array is just a series of variables, and in this case they are start[0], start[1], start[2] ..., start[18], start[19] (20 variables starting from 0). It is an easier way to define 20 variables without typing a different name for each one. Also, it helps when you don't know which particular one you want to use in advance.

By now you have probably noticed the twenty and thought well if we are not supposed to directly use the 'Y', then we shouldn't directly use the 20 also, and you are right! It would be better defined as:

const int LastLine = 20;
int start[LastLine];
int end[LastLine];

This way in the future if we decide to make changes to the screen, for example, expand the amount of lines it shows, we can just change the variables. You might never make such changes often in a program this small, but in bigger projects doing this will save a lot of time and grief, especially when one variable controls the actions of hundreds of statements and functions.

Now we need to decide what the pit will be made out of. Obviously a bunch of k's or o's wouldn't look very good, so we are going to use one of the extended characters. Character 219 is a solid block, hence:

const int block = 219;

Next we will define the variables we will use to do the timing.

int timeCounter = 0;
clock_t timeRate = 0.5 * CLOCKS_PER_SEC;

We will use timeCounter to keep track of how much time has passed sense the beginning of the program, and timeRate to decide how much time will pass between updates; in this case its going to be half a second. Many compilers have a different amount of clock ticks they generate per second, so they all (if they follow the standard) will have a constant called CLOCKS_PER_SEC that contains the value of how many clock ticks there are per second. By multiplying .5 by the constant, timeRate will hold how many ticks occur every half second.

The variable timeRate is declared as a clock_t, since CLOCKS_PER_SEC is also a clock_t. clock_t is a type declared in <ctime> used to represent times. As, clock_t is in namespace std we will use the declaration

   using std::clock_t;

so that we can refer to it.

The time routines are part of the C++ standard library. Since it is a library, even though its standard, you have to include it in your source code through a header file. This header file lets the compiler know how to recognize the timer functions when you use them. All you have to do is add the #include to the top of your source code and the compiler will do the rest.

#include <ctime>

You might be wondering if that line is a typo, but nope, you do not need the ';' at the end of the #include like you do everything else. If you do include it, your file will probably not compile at all.

Now, lets start coding something other than variables. First we are going to make it so that the program will run until you press escape (escape = key 27). We will use the while(); control statement. You can use it to do something while a condition is true (like escape not being pressed). We have not yet defined a variable to store what key has currently been pressed, so we will just do them both at the same time.

int key = 0;

while (key != 27)
{
   //Statements here will be executed until escape is pressed
}

Your source code should now look like this

#include <ctime>
using std::clock_t;

int main()
{
   const char Person = 'Y';

   int personX = 39;
   int personY = 5;

   const int LastLine = 20;
   int start[LastLine];
   int end[LastLine];

   const int block = 219;

   int timeCounter = 0;
   clock_t timeRate = 0.5 * CLOCKS_PER_SEC;

   int key = 0;

   while (key != 27)
   {
   }

   return 0;
}

Within the while(); control statement we are first going to place the functions that will update the state of the key. This code can be compiled right now, but without a way to update the key variable, it will go on forever, since the variable key will never equal 27 (esc). Luckily for us the standard library contains a few ways to interact with the keyboard.

#include <conio.h>      //add this line at the very top

while (key != 27)
{
   if (kbhit())
   {
      key = getch();
   }
}

return 0;

The header file conio.h includes commands designed specifically for console input and output. This includes the kbhit() function. What kbhit() does is returns a true if there is a key waiting in the keyboard buffer (where keys go when they are pressed), otherwise it returns false. So if kbhit() is true then, and only then will it execute "key = getch();". The function getch() gets the next character from the keyboard buffer and returns it as an integer (int). In order to collect this value, we set key equal to it.

The reason the function getch() is inside the if control statement testing whether a key has been hit or not is because getch() will wait for a key to be pressed, if no key has already been pressed. This is a killer when it comes to any game implemented in real time, so this way getch() will only be executed when it does not have to wait for a character under this scheme.

Now you can compile the code and it will sit there, not letting you do anything until you press escape.

Next we should figure out what keys the keyboard buffer reports were pressed when you use the arrow keys. Two keys are reported, but different compilers can report different keys2. We are going to modify the loop like this:

#include <iostream>   //you should also add me to the very top

using namespace std;

while (key != 27)
{
   if (kbhit())
   {
      key = getch();

      cout << key << endl;
   }
}

The header <iostream> includes the cout object. The "using namespace std;" declares that you are using the standard namespace. If you have trouble compiling it, and get some error about a non existing namespace, then you should try to get a compiler and library that conforms to ISO C++ standard. If you can't, removing the line might work. If you do require that line, you could drop it and write "cout" as "std::cout" instead, but this way there is only one line of difference between the compilers that do, and do not need it, which makes this easier to teach2. It also saves use from having to type "std::" over and over again.

Now when you compile and run it, you shall see a screen, or a dos box, which is totally blank until you press a key. When that happens, its corresponding key codes will get printed. You can play with this till your heart's content, but we are only interested in 4 key codes, which are the up, down, left, and right arrow keys. Press them all and right down your numbers. Make absolutely sure you have them right, and remember them; we will use them later.

Next we are going to set up the timing routines! The standard timing routines are a little weird, but easy to use. The clock() function will start counting on its first use, hence setting it equal to our timeCounter variable should do the trick. It also insures that our timer starts at zero too; you can never be too prudent3.

timeCounter = clock();

After the first use of the clock() function it will return the amount of ticks since its first use. We can therefore compare it to our timeCounter variable to see when clock() returns a greater value than timeCounter contains (ie which means a certain amount of time has passed). We can use the if(); control statement to test for it.

When that time has passed, then we will have to add our timeRate to our timeCounter, so it will take clock() another 0.5 seconds to become bigger than our timeCounter again. We can use += for that, which means timeCounter = timeCounter + timeRate; its just a lot easier!

while (key != 27)
{
   //Manage Keyboard
   if (kbhit())
   {
      key = getch();
   }

   //Manage Timing
   if (timeCounter - clock() < 0)
   {
      timeCounter+= timeRate;

      cout << "1/2 seconds pass... " << endl;
   }
}

You may have noticed, you can now take out the statement that prints the key codes. To test our routines you should also add the statement that says "1/2 seconds pass...". It will print every 1/2 seconds.

Source Code Check: ("It should look something like this.")

#include <ctime>
#include <conio.h>      //bug: Working On This, need alternative
#include <iostream>

using namespace std;

int main()
{
   //Variable Declarations
   const char person = 'Y';
   int personX = 39;
   int personY = 5;

   const int LastLine = 20;
   int start[LastLine];
   int end[LastLine];

   const int block = 219;

   int timeCounter = 0;
   double timeRate = 0.5 * CLOCKS_PER_SEC;

   int key = 0;

   //Extra Setup
   timeCounter = clock();

   //Main Loop
   while (key != 27)
   {
      //Manage Keyboard
      if (kbhit())
      {
         key = getch();
      }

      //Manage Timing
      if (timeCounter - clock() < 0)
      {
         timeCounter+= timeRate;

         cout << "1/2 seconds pass... " << endl;
      }
   }

   return 0;
}

If you have not already, it would be a good idea to compile this to see if it works. If it does not work, and you have exactly what is above, speak to your instructor, sometimes weird things happen.

Next we are going to implement displaying our person, and the arrow key routines! What fun!



1 Democracy is fun.
2 Verses making this two chapters... Note: Your instructor can specify these things for you if you are not sure.
3 Well, until you start turning out ultra slow software, then you're being too prudent.