Functions
A function is a named piece of code that takes values, computes something and returns a value with return. Write one when a solution does the same computation in several places or for many values, such as a digit sum or a primality check inside a loop.
Explanation
A program must say which of two numbers, 507 and 38, has the larger sum of digits. Without functions, the loop that adds up the digits is written twice: n % 10 is the last digit, and n /= 10 drops it (integer division). Then an if compares the two sums:
int a = 507, b = 38;
int sa = 0;
while (a > 0) {
sa += a % 10;
a /= 10;
}
int sb = 0;
while (b > 0) {
sb += b % 10;
b /= 10;
}
if (sa > sb) cout << "first";
else cout << "second";The two loops are the same, and only the names change. A function lets you write the loop once and use it for any number:
int digitSum(int n) {
int s = 0;
while (n > 0) {
s += n % 10;
n /= 10;
}
return s;
}
// in main:
int a = 507, b = 38;
if (digitSum(a) > digitSum(b)) cout << "first";
else cout << "second";The parts of the function have these names:
intbefore the name is the return type, the type of the returned value.digitSumis the name.int nis the parameter. A function can have several, separated by commas.The code in braces is the body.
returnends the function.
The value written in a call, such as a in digitSum(a), is the argument. A call runs the body with each parameter set to a copy of its argument, and then the call is replaced by the returned value. Library functions such as max(a, b) and sqrt(x) work the same way.
Because a call is replaced by its returned value, it can stand anywhere a number can: in a condition, in a sum, or as the argument of another call. In digitSum(digitSum(9999)) the inner call runs first and returns 36, and the outer call gets 36 and returns 9.
Fig. 1. The inner call runs first, and its returned value is the argument of the outer call.
Let's follow one call step by step. Step through it and watch n and x.
int x = 507;
int s = digitSum(x);
cout << x << ' ' << s;int x = 507; puts 507 into x. The box is main, and its s has no value yet.
Fig. 2. Step through the call with the buttons or the arrow keys. Blue cells have just changed, and a grey box is a call that has ended.
The parameter n started as a copy of x, so the loop could make n zero while x stayed 507.
Both functions also have a variable named s, and they are two different variables. A variable declared inside a function is a local variable: it belongs to that call, and other functions can't see it. Parameters are local variables too: n is created at the call and disappears when the call ends.
References
Sometimes a function must change the caller's variables. Say a program has two numbers, x = 3 and y = 8, and must swap them. A first try is a void function that swaps its two parameters:
void swapValues(int a, int b) {
int t = a;
a = b;
b = t;
}
// in main:
int x = 3, y = 8;
swapValues(x, y);
cout << x << ' ' << y;It prints 3 8. The function swapped its own copies, a and b, just as n changed in digitSum while x stayed 507.
To make the function work on x and y themselves, write & after the type of each parameter:
void swapValues(int& a, int& b) {The & makes the parameter a reference, another name for the variable passed in. Now a is x and b is y, and the same body prints 8 3.
Fig. 3. Red: the copies were swapped. Blue: a and b name the cells of x and y.
This is called passing by reference, and a normal parameter is passed by value. An argument passed by reference must be a variable, so swapValues(x, 5) doesn't compile. The library function swap(x, y) already does this job, and it takes its parameters by reference too.
Returning early
return ends the function at once, even in the middle of the body. So a function can have several returns, and the first one reached gives the returned value:
int sgn(int x) {
if (x > 0) return 1;
if (x < 0) return -1;
return 0;
}For sgn(-4) the second line returns -1, and the last line never runs. A void function has no value to return, but it can still leave early with return;.
In C++
// return type, name, parameters (copies)
int bigger(int a, int b) {
// body: compute the returned value from the parameters
if (a > b) return a;
return b; // return: the call is replaced by this value
}
void order(int& a, int& b) { // & : works on the caller's variables
if (a > b) swap(a, b);
}In a complete program the function goes above main, and main calls it once for each number. The input has t, then t numbers, for example:
3
507
1000
99#include <iostream>
using namespace std;
int digitSum(int n) {
int s = 0;
while (n > 0) {
s += n % 10;
n /= 10;
}
return s;
}
int main() {
int t;
cin >> t;
for (int i = 0; i < t; i++) {
int n;
cin >> n;
int s = digitSum(n);
cout << s << '\n';
}
}For a yes-or-no question, return bool. A loop can call such a function, for example to count the primes up to n. Divisors up to \sqrt{n} are enough, so the loop in isPrime stops when i * i > n:
bool isPrime(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return false;
}
return true;
}
// in main, after reading n:
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (isPrime(i)) cnt++;
}Three calls of order put three numbers in increasing order:
int a = 7, b = 2, c = 4;
order(a, b);
order(b, c);
order(a, b);For 7 2 4 the first call gives 2 7 4 and the second gives 2 4 7. The third call is needed for inputs such as 4 7 2, where the second call moves 2 into the middle.
Common mistakes
Printing instead of returning. With
int bigger(int a, int b) { if (a > b) cout << a << ' '; else cout << b << ' '; }, the linecout << bigger(3, 8) + 1;printed8and then a meaningless number, because the call returned no value. Return the value and letmainprint it.Returning in both branches inside a loop. With
if (n % i == 0) return false; else return true;the loop stops after checking 2, soisPrime(9)returnstrue. Putreturn true;after the loop.A parameter type too small for the computation.
long long f(int x) { return 1 + x + x * x; }returns -486618623 forx = 1000000000, becausex * xis computed inint, which holds numbers only up to about 2 \cdot 10^9, and only then becomeslong long. Make the parameterlong long x(integer types).
Similar techniques
Recursion is a function that calls itself on a smaller case, and each call has its own copies of the parameters.
Sorting with your own order passes a comparator, a function that returns
bool, tosort.Arrays and vectors should be passed as
const vector<int>&when the function only reads them, so they aren't copied.
Practice
Very easy · Implementation
Very easy · Math
Very easy · Brute force
Very easy · Math · Implementation
Very easy · Implementation
Very easy · For Beginners
Very easy · Number theory
Very easy · Math
Very easy · Implementation