Example: The function countdown(n)
prints the numbers from n
down to 0
.
#include <iostream>
using namespace std;
void countdown(int);
int main() {
int start = 5;
countdown(start);
// what is the value of 'start' at this point?
}
void countdown(int n) {
while(n>=0) {
cout << n << endl;
n--;
}
}
5
4
3
2
1
0
What is the value of the variable start
in the main function
after the function call countdown(start)
?
Is it still equal to 5
or equal to 0
?
When you call the function countdown(start)
,
the formal parameter of the function (n
) is created
as a brand new variable, a chunk of memory is allocated for it,
and the value of the argument (in this case, the number 5
) is
copied to it.
So, when you call the function, it gets its own independent copy of all the arguments passed to it.
Thus any change to the parameter (for example, the statement n--;
in this case), would affect
only the local copy of the passed value, not the original value of the variable start
.
Therefore, after the function call, the value of the variable start
remains unchanged and
equal to 5
.
This approach, when you pass the argument by value is called Call by value. And it is a really great idea! Because a function is an independent module of your program, and it sould not inadvetantly affect the variables declared somewhere else in the program. The only result of the function sould be just the value it returns.
In the perfect world, this would be enough.
Sometimes, we want our function to return multiple values, not just one.
Because C and C++ don’t have a good built-in tuple type there is no easy way to return multiple values from the function. So, you might want to emulate this behavior by passing multiple variables to a function, which will assign values to them.
void get_coords(int location, int &x, int &y) {
x = location % 10;
y = location / 10;
}
Sometimes, making a whole new copy of the argument is too expensive.
If the argument is a huge object stored in a variable, then it might be desirable to pass a reference to that variable without making its new local copy (which can be a waste of memory and CPU resources).
int object_dimensions(huge_object &obj) {
return obj.width * obj.height;
}
Example: Function make_even(x)
increments its argument x
if it is odd.
The argument is passed by reference.
#include <iostream>
using namespace std;
void make_even(int &x);
int main() {
int x = 5;
make_even(x);
cout << "x = " << x << endl;
}
void make_even(int &x) {
if (x % 2 == 1)
x = x + 1;
}
x = 6
Example: Function normalize(x,y)
normalizes
the vector (x,y) by dividing it by its Euclidean norm sqrt(x2 + y2).
The function updates its arguments x
and y
in place (they are passed by reference).
#include <iostream>
#include <cmath>
using namespace std;
// normalize components of the vector (x,y)
bool normalize(double &x, double &y);
int main() {
double x = 1.5, y = -0.7;
normalize(x, y);
cout << "x = " << x << endl << "y = " << y << endl;
}
bool normalize(double &x, double &y) {
double len = sqrt(x*x + y*y);
if (len > 0.0) {
x = x / len;
y = y / len;
return true;
}
else
return false;
}
x = 0.906183
y = -0.422885
swap(a,b)
#include <iostream>
using namespace std;
void swap(int &a, int &b);
int main() {
int x = 5, y = 10;
cout << "x = " << x << ", y = " << y << endl;
swap(x, y);
cout << "x = " << x << ", y = " << y << endl;
swap(x, y);
cout << "x = " << x << ", y = " << y << endl;
}
void swap(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
}
x = 5, y = 10
x = 10, y = 5
x = 5, y = 10
Write a function
void rational(double x, int &n, int &d);
which for the given positive double x
, searches for the numerator n
and denominator d
that are positive integers <= 10000, such that the error |x - n/d| is the smallest possible.
const
call by referenceWith a constant call by reference, we can avoid copying the argument, at the same time not allowing to make any changes to this argument.
int compute(const int &arg);
Multiple functions can be defined using the same name, however they must differ either
Notice that the difference in the type of the value returned is not enough to allow an overloaded definition.
The overloaded function definitions must differ in their formal parameters.
#include <iostream>
using namespace std;
double average(double x1, double x2);
double average(double x1, double x2, double x3);
int main() {
cout << average(5, 10) << endl;
cout << average(12, 13, 15) << endl;
}
double average(double x1, double x2) {
return 0.5 * (x1 + x2);
}
double average(double x1, double x2, double x3) {
return (x1 + x2 + x3) / 3.0;
}
7.5
13.3333
#include <iostream>
#include <cmath>
using namespace std;
// vector length (Euclidean norm) for 1D, 2D, and 3D
double length(double x, double y = 0.0, double z = 0.0);
int main() {
cout << length(4,3,5) << endl;
cout << length(7,4) << endl;
cout << length(10) << endl;
}
double length(double x, double y, double z) {
return sqrt(x*x + y*y + z*z);
}
7.07107
8.06226
10