- HubPages»
- Technology»
- Computers & Software»
- Computer Science & Programming
C++ Functions : A Practical Guide (CPP)
Prerequisites
Before you can understand functions in C++, you should have at least a basic grasp of how to declare and use variables, and how to perform basic calculations.
If you have troubles with these topics, I suggest going through some of my tutorials on C++. Lessons 1, 2, and 3 would be helpful in order to have enough knowledge and skill in C++ to at least understand the basics of this article.
What is a function, and why do I really need to use them?
A function in C++ is a reusable group of statements that can be executed one or more times throughout a program.
An incredibly important idea in software engineering, and thus, most programming languages is reusability. This means that, you design and implement a well defined set of statements that perform a specific task (or tasks), and use them more than once.
Even if you are only planning on performing a particular set of operations very few times, or even only once, you should still break your program up into functions to keep the program more readable and cleaner.
The "Squaring Machine"
We can think of a function as a machine. From the outside, we don't really care about the inner workings. For right now, let's concentrate on what the "machine" does, not how it does it.
In the above diagram, we see the results of different input going into the "Squaring Machine". For example, when 2 goes in (input = 2), 4 comes out (output). When 3 goes in, 9 comes out. And finally, when 4 goes in, 16 comes out.
So, the machine performs the task of squaring a number. Any number you give it, it will return the square of that number.
Now, let's develop a syntax to represent our Squaring Machine. Let's say that
Square(input) = output
represents our squaring machine (function) and that it takes a number as its input, and returns a number as its output.
So, to represent the diagram above, we can use our new syntax this way:
- Square(2) = 4
- Square(3) = 9
- Square(4) = 16
Now, we're getting closer to how C++ actually looks. So, we know how to call or execute our Square() function. So we know what it does. But now, we need to be concerned with how it does it.
Square Function
Let's review what we know so far:
- The Square function takes input
- It squares the input
- It returns the output
Okay, well let's concentrate more on what it means to square a number.
Squaring a number is really just taking that number and multiplying it by itself. So, in general, our Square function works like this:
Square(n) = n * n
The number n is the input to the Square function, and n * n is the output.
Now we know the what and the how of our Square function (a.k.a. "Squaring Machine").
Now, how do we translate this into C++?
#include <iostream> using namespace std; int Square(int num); //function prototype int main() { //function calls: cout<<Square(2)<<endl; cout<<Square(3)<<endl; cout<<Square(4)<<endl; return 0; } //function definition: int Square(int num) { return num * num; }
We must note a few things in the above code for the Square() function.
First, this particular version of the Square() function has an int return type, and also takes an int parameter. You can very easily convert this code to take float or double variables.
Here are three major things you must know about functions:
- Function prototype (the function declaration)
- Function call
- Function definition
The function prototype comes before the main() function, near the top of the program. While you could just put the entire function body of Square() before main(), it is poor programming style to do so. main() should be the first function that is fully defined in your program.
So, function prototypes give the compiler a "head's up" about a function that you will define later in the program.
The function call or function invocation is when the function is actually used.
The function definition is where the actual "guts" of the function are located. This is the inside of our "Squaring Machine", if you will.
Here are some important function-related phrases that trip up students (and often, even professionals):
- Parameter vs. Argument
- Formal Parameter vs. Actual Parameter
Parameter vs. Argument and Formal Parameter vs. Actual Parameter
Sometimes the plethora of phrases alone can trip up even the most experienced of programmers. Hopefully this section will help with understanding the differences between these "parameter-related" phrases.
First, it is important to note that there are two naming systems involved here, and usually programmers will favor one over the other. But, this is also the reason people get tripped up so easily.
The parameter, also called the formal parameter is the "placeholder" variable that is present in the function prototype, and the function definition. In both the function prototype and the function definition, we don't know what the actual value that we'll be dealing with will be. So, the parameter (formal parameter) is a placeholder for this value.
The argument, or actual parameter is the actual value (or variable containing a value) that is passed in to the function. The argument (actual parameter) is what is passed to the function during the function call (function invocation).
So, as an example:
int Square(int num);
num is the parameter (formal parameter) to the function, Square().
Later, in the main function, we actually call the function, like this:
Square(2);
In this case, 2 is the argument (actual parameter) to the Square() function.
So, to summarize this particular set of phrases:
- The argument is the same as the actual parameter
- The parameter is the same as the formal parameter
If you have trouble keeping these straight, a helpful (albeit cheesy) mneumonic device for this would be:
"Don't argue with an angry paratrooper" (argument = actual parameter)
So if you can keep that mneumonic straight, you'll know the other phrase, so you won't mix them up.
Pass by Value vs. Pass by Reference
There are two ways to pass an argument to a function:
- Pass by Value
- Pass by Reference
Pass-by-value (also called pass-by-copy) means that the argument is copied and the copy becomes a local variable of the function.
Pass-by-reference means that the argument's address is passed to the funciton. Thus, if you modify the variable inside the function, when you return from the function, the value of that variable will remain modified.
Code Sample of Pass by Value vs. Pass by Reference
#include <iostream> using namespace std; void passByValue(int someNumber); void passByRef(int& someNumber); int main() { int myFirstNumber = 10; int mySecondNumber = 20; //pass by value: cout<<"At the beginning, myFirstNumber is equal to : "<<myFirstNumber<<endl; passByValue(myFirstNumber); cout<<"After I call passByValue(), myFirstNumber is : "<<myFirstNumber<<endl; cout<<endl<<endl; cout<<"At the beginning, mySecondNumber is equal to : "<<mySecondNumber<<endl; passByRef(mySecondNumber); cout<<"After I call passByRef(), mySecondNumber is : "<<mySecondNumber<<endl; return 0; } //function definition: void passByValue(int someNumber) { someNumber = 7; } void passByRef(int& someNumber) { someNumber = 7; }
Examining the code, we see that we have two functions:
- passByValue()
- passByRef()
The function names are not important. We could call one Curry() and one Sausage(), and they would still do the same thing. But, it's helpful to have useful names.
Moving on, we see that there are function prototypes near the top of the program, then the definition of the main function, and finally, the function definitions for our two functions, passByValue() and passByRef().
Notice the similarities and differences between the two functions. They both have the same statement inside of them:
someNumber = 7;
The variable someNumber is what each of these functions refers to the argument as once it is passed into the function. In other words, it's the local name of the variable that was passed in. It does not have to match the name of the variable that was passed in by the calling function. In fact, the above code demonstrates this.
Now, the subtle differences are evident in the function prototype, and the function definition. In the function passByValue, we just have a normal parameter without any other symbols. This is pass-by-value.
In the passByRef function, we have the reference operator, &. This says that the parameter that is passed is a reference to an integer, not just an integer. It should be noted that the reference operator is not available in the C programming language, just C++. That being said, C does use the address-of operator, and in that context it is something different than its usage as the reference operator in C++.
So here is a summary of what we know so far:
- passByValue just takes a regular data type (in this case, an integer)
- passByRef takes a reference type (in this case, a reference to an integer)
Even though the function invocations (function calls) are the same, the result is drastically different.
When the two functions are called on myFirstNumber and mySecondNumber, respectively, we see that myFirstNumber is unchanged, but mySecondNumber is changed to 7.
This is because, when myFirstNumber is passed to passByValue(), a copy of it is made. So when someNumber is set to 7 inside of passByValue(), it sets the value of the local variable someNumber to 7, and then when the function ends, the scope of the variable someNumber has ended. The value of the actual parameter, myFirstNumber, remains unchanged.
In the second function, passByRef(), a reference to the actual variable is being passed to the function. A copy is not made. So when the value of someNumber changes, it affects the actual parameter that was passed in, namely mySecondNumber.
Passing Arrays to Functions
For whatever reason, passing arrays to functions seems to be a difficult task for most beginners, and even some professionals slip up and forget how to perform this very important operation.
There are a couple ways to pass an array to a function. Examine the code below carefully.
#include <iostream> using namespace std; void passArray(int* arrayParam, const int SIZE); void anotherWay(int arrayParam[], const int SIZE); int main() { const int SIZE = 5; int myArray[SIZE]; //initialize the array for(int i = 0; i < SIZE; i++) { myArray[i] = i; //assign the value i to the index of array at i } //print out the initial values: cout<<"Initial values of our array: "<<endl; for(int i=0; i < SIZE; i++) { cout<<myArray[i]<<endl; } //now call the function to change the values: passArray(myArray, SIZE); //now print the values in the array after the function: cout<<endl<<endl; //add a little more whitespace cout<<"After the function, the values are:"<<endl; for(int i=0; i < SIZE; i++) { cout<<myArray[i]<<endl; } //now, call the anotherWay function anotherWay(myArray, SIZE); cout<<endl<<endl; cout<<"After anotherWay function, the values are:"<<endl; for(int i=0; i < SIZE; i++) { cout<<myArray[i]<<endl; } return 0; } //one way to pass an array to a function void passArray(int* arrayParam, const int SIZE) { for(int i=0; i < SIZE; i++) { arrayParam[i] = 2; } } //another way to pass an array to a function void anotherWay(int arrayParam[], const int SIZE) { for(int i=0; i < SIZE; i++) { arrayParam[i] = 100; } }
If we observe in the code sample and the output above, we see that initially, our array contains:
0, 1, 2, 3, 4
We can declare a function to take an array as a parameter in two different ways:
- By passing a pointer to the array (technically to the first element in the array), using the * operator
- By using brackets [ ]
In each case, you are essentially passing a pointer to the first element in the array to the function. And when C++ allocates memory for an array, we can treat it as if it were contiguous. So, as long as we have the address of the first element in the array (a pointer to the array itself), we can access the other elements as well.