Lesson 7 – Functions and Header Files

Divide and conquer!
Latin Idiom

Practical Programming

You are already familiar with the main() function (_tmain() in Visual Studio dialiect). This is a special function that is automatically executed when program starts. As your program gets bigger, the main() function grows and it gets harder and harder to understand the code. You can fight the complexity by creating your own custom functions. You break apart your code and make it easier to understand.

As with everything else in C/C++, you must define a function before you can use it. Let’s take a look at this example:

// a function that calculates factorial
int factorial(int n) {
    int res = 1;
    int ii;

    for(ii = 1; ii <= n; ++ii) {
        res = res * ii;
    }
    return res;
}

This function calculates a factorial of the integer number. After you defined a function, you can call it with different actual parameters:

int main(int argc, char** argv) {
    int z;

    z = factorial(10);
    cout << “Factorial of 10 is “ << z << endl;

    cout << “Enter a number:” << endl;
    cin >> z;
    cout << “Factorial of “ << z << “ is “ << factorial(z) << endl;

    return 0;
}

The function definition consists of the following items:

  • the function name (similar to variable names rules apply: function name must start from a letter, contain only letters, digits and underscore ‘_’ and be unique);
  • the function input parameters definition (what functions expects);
  • the function return type (what should be expected back);
  • the function implementation (body).
return_type function_name(input_parameters_list) {
    function_implementation
}

Our factorial function from the example above has name “factorial”, it requires one integer input parameter (“int n”) and returns an integer (“int”).

A special return type “void” is used to indicate that a function has no return parameters:

void print_result(int step, float res) {
    cout << “On step “ << ii << “ the result is “ << res << endl;
}

This function has two input parameters: first of type int and second of type float. When you call a function you must make sure that actual parameters have correct types:

print_result(10, 0.345); // correct
print_result(11, “some string”); // incorrect: compiler error “type mismatch”

A special keyword “return” is used inside the function body to stop the function execution immediately and return the value to the caller. A non-void function must return a value on all execution paths. The following function will generate compiler error: if a is equal to b then there is no “return” value:

int foo(int a, int b) {
    if(a < b) {
        cout << “a is less than b” << endl;
        return -1;
    } else if(a > b) {
        cout << “a is greatre than b” << endl;
        return 1;
    }

    cout << “a is equal to b” << endl;
    // compiler error - no return value!!!
 }

A void function can use return statement to exit from the function early w/o returning anything:

void bar(int x) {
    if(x <= 0) {
        return; //  if x <= 0 then function stops here
     }
     cout << “The x is positive” << endl;
}

When you are doing step-by-step debugging of a program with functions, you can either step over the function call or step into the function call to execute a function step-by-step with actual parameters for this call.

Large programs contain multiple files. To make defined functions from one file visible in another file, programmers separate function declaration and function implementation. The function declaration is placed in a header file (which usually has .h extension):

// File factorial.h

int factorial(int n);

and function implementation in the source file (which usually has .cpp extension):

// File factorial.c

#include “factorial.h”

// a function that calculates factorial
int factorial(int n) {
    int res = 1;
    int ii;
    for(ii = 1; ii <= n; ++ii) {
        res = res * ii;
    }
    return res;
}

The include command is used to insert into the current file the content of included file “as-is”. Now you can use your function anywhere!

// File program.cpp
#include “factorial.h”

int main(int argc, char* argv[]) {
   cout << “Factorial of 10 is “ << factorial(10) << endl;
}

You probably noticed that we’ve used include command before to load function definitions from the standard C/C++ libraries:

#include <iostream>
#include <stdlib.h>
#include <math.h>

Note that we used quotes to load our custom header file

#include “factorial.h”

and less/greater brackets to load standard C/C++ header files. The reason for this difference is the C/C++ compiler algorithm for locating the correct file on disk. For now, just follow this convention: custom header files from the same project should be included with quotes and standard header files from C/C++, Windows, etc. should be included with less/greater brackets.

The process of modifying the source code to make it more readable and more maintainable is called re-factoring. Separating the code into re-usable functions and breaking apart big files into smaller files is one of the easiest ways to re-factor your code.

Exercises

1 ) Re-factor your Fibonacci program and create a function for calculating the Fibonacci number.
2) Re-factor your GCD (greatest common divisor) program and create a function for calculating the GCD.
3) Re-factor your factorial program and create a separate header/source files for the factorial function. Use “Project” / “Add File” menu in Visual Studio to create new files. Don’t forget to add new files to git before committing your changes!

 

Posted in Practical Programming | 1 Comment

Lesson 6: Source Control System – GIT

Better be safe than sorry!
English Idiom

Practical Programming

Writing a program is usually a trial-and-error affair. Thus, it is really important to be able to easily undo your changes and rollback to the previously known good version. In the early days of programming, this was achieved by creating a complete copy of a project. Today, we have source control systems that simplify and optimize this process.

A source control system (SCM) tracks changes in a set of files (a project). To record your changes in the SCM, you execute a commit operation. After you commit you changes, you can quickly go back to the exact state you’ve been at the time of the commit.

We are going to use git as our primary SCM (there are many others!). Git has many interesting features but we will start from basics. To install git, install Cygwin – set of command line tools for Windows. Make sure to mark git package for installation!

First, you will need to tell git who you are. You will need to do this step only once. Open the Windows console (run cmd.exe) or a Cygwin shell window and execute the following commands:

git config --global user.name “<your name>”
git config --global user.email “<your email>”

If you like pretty highlighting, then don’t forget to configure git to use colors:

git config --global color.status auto
git config --global color.branch auto

Next, you will need to create a git repository for one of your projects:

cd <your project folder>
git init

Right now the repository is empty. Let’s add your source files to git. There is no need to add files produced by the compiler/linker (usually, they will be placed into Debug sub-folder), they can be re-created. However, don’t forget to add your Visual Studio project files. If you will add new files to your project in the future, make sure to add them to git!

git add <list of files to add>

Now is the most important step. Let’s commit your changes and save them permanently. For every commit, you specify a “commit message” (specified after -m flag) that briefly describe your changes. It is important to have good descriptive commit messages to make sure you can figure out what you’ve changed long time after you made the change):

git commit -a -m “Initial commit”

The -a command line option tells the git to commit all changed files you’ve previously added. You can also commit just some files

git commit -m “<commit message>” <list of files to commit>

To verify our commit, let’s check the log

git log

This command will print the commit ID (long string of numbers and letters), the commit author (you!), the commit date and the commit message (“Initial commit”).

When you are working on a project, you can view what did you change since last commit. This is very useful and helpful tool:

git status
git diff

At any moment, you can “undo” your current changes (they will be lost!) and get  a previously committed version of a file:

git checkout <filename>

Finally, you can easily add/copy/move/remove files in git using the following commands:

git add <filename>
git cp <filename>
git mv <filename>
git rm <filename>

To use git to its full advantage, make sure to add all your files to git and commit every time you feel the change you just made is working. There is no harm in having too many commits!

Exercises

1) Create git repositories to 3-4 of your projects. Make sure to add Lunar Model game!
2) For one of the projects try to

  • modify one or more files;
  • view diff of your changes;
  • commit your changes;
  • view the log of your commits.
Posted in Practical Programming | 1 Comment

Lesson 5: Loops – Lunar Lander Game

Houston, we have a problem!
Apollo 13

Practical Programming

Today, we will use everything we learned so far to write the Lunar Lander Game. The objective of the Lunar Lander Game is to land a lunar module on the moon surface. To win the game, the module should touch down the moon with the vertical speed smaller than 5 feet/min. The module vertical speed is controlled by using the thrusters that spend a limited amount of available fuel.

We are going to build a step-by-step game. On each step game should print on the screen the current module’s altitude, vertical speed, and remaining fuel. The user enters 1 to fire thrusters or 0 to skip the turn:

Time: 23 secs
Altitude: 20000 feet
Vertical Speed: 1000 feet/min
Fuel Remaining: 2200 lbs
Please 1 to fire thrusters or 0 to skip the turn: _

The game then recalculates the values, prints the new values on the screen and waits for user input again. The process continues until the game ends when altitude becomes less or equal to zero. The player wins if at the end of the game the module vertical speed is less than 5 feet/min and the player loses if it is greater than 5 feet/min.

To write the game, you will need formulas to calculate altitude, vertical speed and used fuel:

  • if user enters 1 and thrusters fire:
FM  = FM  – ∆T * FED
VS  = VS  – ∆T * Isp * ln((RM + FM + ∆T * FED) / (RM + FM)) + ∆T * G
ALT = ALT – ∆T * VS
  • if user enters 0 and thrusters do not fire:
FM  = FM
VS  = VS + ∆T * G
ALT = ALT – ∆T * VS

where

FM    - the current fuel mass (lbs)
VS    - the current vertical speed (feet/sec)
ALT   - the current altitude (feet)
∆T    - the step duration (constant, sec)
RM    - the rocket mass w/o fuel (constant, lbs)
FED   - the fuel exhaust velocity (constant, lbs/sec)
Isp   - the fuel exhaust impulse (constant, feet / sec^2)
G     - the lunar gravity (constant, feet/sec^2)

You will need select the values for various constants (initial altitude, initial fuel mass, rocket mass, lunar gravity, ∆T, fuel exhaust impulse and velocity). Try to find some constants with google and then try different values for others to make the game fun to play.

Note that fuel mass (FM) can’t go negative. Make sure your program checks for that.

You will need to use ln() function to calculate natural logarithm. Add

#include <math.h>

near the top of your program outside the main() function to load the definition for ln() function.

To make the game easier to play, consider clearing the screen before each step. Add

#include <stdlib.h>

near the top of your program outside the main() function and use the following code to clear the screen:

system("cls");

Exercises

1) Write Lunar lander game and find constants that make it fun to play.

 

Posted in Practical Programming | 1 Comment