void
. Functions that don’t return anything.If a function does not return anything, we say that it’s result type is void
.
Usually such functions are called for their “side-effects”
(they are performing some interaction with the outside world: printing on the screen, writing to a file,
changing global varaibles, etc.)
Example: a void function report
that prints the answer on the screen and does not return anything.
#include <iostream>
using namespace std;
// reports the answer
void report (int v);
int main() {
// compute the answer
int answer = 5 + 6;
report (answer);
return 0;
}
void report (int v) {
cout << "The answer is " << v << endl;
// a function returning void, does not need a return statement,
// but you can add it (with no values to be returned)
return;
}
The answer is 11
Local variables and blocks. It’s easy, actually, a variable lives only within the block ({ ... }
)
it was declared in, and is destroyed as soon as the block ends.
In C++, a variable can be overshadowed by another variable inside a nested scope
{
int x = 0;
{
int x = 1;
cout << x; // prints 1, not 0
}
}
A function must be declared before it can be used. (This is why we forward declare all our functions at the very beginning of the file, and define them later).
C++ does not allow nested functions definition.
A variable can be defined with the const
modifier. Such varaible is called a constant,
and its value cannot be changed.
Example: In the following example, the assignment to the constant fails (we are getting an error at the compile time):
int main() {
const int SOME_VALUE = 0;
SOME_VALUE = 1;
}
g++ p4const.cpp
p4const.cpp: In function 'int main()':
p4const.cpp:5:5: error: assignment of read-only variable 'SOME_VALUE'
SOME_VALUE = 1;
^
Example: A function uid()
returns unique user IDs. It’s using a global variable last_uid
to maintain its state.
#include <iostream>
using namespace std;
// returns a unique user id
// keeping track of its state using a global variable
int uid();
int last_uid = 0;
int main() {
// make 3 users:
int alice_uid = uid();
int bob_uid = uid();
int carol_uid = uid();
cout << "Alice. UID = " << alice_uid << endl;;
cout << "Bob. UID = " << bob_uid << endl;;
cout << "Carol. UID = " << carol_uid << endl;;
}
int uid() {
last_uid ++;
return last_uid;
}
Alice. UID = 1
Bob. UID = 2
Carol. UID = 3
A more complex example: Print 10 first prime numbers. We use a globlal variable to
maintain the state of the function next_prime()
between the function calls.
#include <iostream>
#include <cmath>
using namespace std;
// returns true if x is a prime, and false otherwise
bool is_a_prime(int x);
/* returns a next prime number
every time the function 'next_prime' is called
it returns a new prime number and saves it in the
global state variable 'prime'
*/
int next_prime();
// a global variable, keeps track of the most recently
// returned prime number
int prime = 0;
int main () {
// print first 10 prime numbers
for (int i = 0; i < 10; i++) {
cout << next_prime() << endl;
}
return 0;
}
bool is_a_prime(int x){
if (x <= 1)
return false;
for(int i = 2; i <= sqrt(x); i++) {
if (x % i == 0)
return false;
}
return true;
}
int next_prime(){
do {
prime++;
} while ( !is_a_prime(prime) );
return prime;
}
2
3
5
7
11
13
17
19
23
29
Avoid global state if possible. Usually it’s possible.
Compute the sum of 1 + 2 + 3 + … + 100.
An iterative implementation (using a loop)
#include <iostream>
using namespace std;
// iteratively compute the sum: x + ... + y
int compute(int x, int y);
int main() {
cout << compute(1, 100) << endl;
return 0;
}
int compute(int x, int y) {
int sum = 0;
for (int i = x; i <= y; i++) {
sum += i;
}
return sum;
}
5050
A recursive implementation
Based on the observation that:
Sum(1,100) =
1 + Sum(2,100) =
1 + 2 + Sum(3,100) = … =
1 + 2 + … + 100
So we can define the function recursively when x <= y:
Sum(x,y) = x + Sum(x+1,y)
#include <iostream>
using namespace std;
// recursively compute the sum: x + ... + y
int compute(int x, int y);
int main() {
cout << compute(1, 100) << endl;
return 0;
}
int compute(int x, int y) {
if (x <= y)
return x + compute(x+1, y);
else
return 0;
}
5050
A better recursive implementation
#include <iostream>
using namespace std;
// A better recursive implementation that allows
// tail-call optimization of the recursive calls.
//
// Compile with the -O2 option (optimization level 2):
// g++ -O2 program.cpp
// recursively compute the sum: x + ... + y
int compute(int sum, int x, int y);
int main() {
cout << compute(0, 1, 100) << endl;
return 0;
}
int compute(int sum, int x, int y) {
if (x <= y)
return compute(sum + x, x+1, y);
else
return sum;
}
5050
Although I should say that g++
actually optimizes the first recursive version as well,
however it may not be able to do so for a more complex recursive function.
Similarly, we can define a function that’s recursively computing the factorial function (n!), or a function computing the nth Fibonacci number.