- Define and call a function with a return type, a name and parameters
- Explain why a function prototype is needed
- Understand that parameters are passed by value (as copies)
- Write a simple recursive function with a base case
You already know two functions well: main, where every program starts, and printf, which prints text. Large programs are made of hundreds of small functions: one calculates a score, one prints a table, one reads a file. Each function does one job, is written once and can be called as many times as you like. And when you find a bug, you fix it in just one place.
How a function is built
- Return type — the type of the result the function gives back (
int,double…). A function that returns nothing usesvoid. - Name — a name that says what the function does, for example
maxorprint_line. - Parameters — the input values written in parentheses together with their types:
(int a, int b). With no parameters you write(void). - Body — the code between the curly braces.
returnsends the result back to the caller and ends the function at once.
The C compiler reads a file from top to bottom. If main calls a function before that function is defined, the compiler has to know about it in advance. For this you write a prototype at the top of the file: the function's header followed by ;.
A declaration that gives a function's name, return type and parameter types, but no body. For example: int max(int a, int b);. Header files such as stdio.h consist mostly of prototypes.
#include <stdio.h>
int max(int a, int b);
double average(int a, int b, int c);
int main(void) {
printf("Max: %d\n", max(12, 31));
printf("Average: %.2f\n", average(5, 4, 4));
return 0;
}
int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}
double average(int a, int b, int c) {
return (a + b + c) / 3.0;
}Max: 31 Average: 4.33
main can stay at the top of the file. Dividing by 3.0 gives a fractional result: 13 / 3 ≈ 4.33.void functions and passing by value
Some functions return no result — they just do a job, such as drawing a line on the screen. Their return type is void. The program below also shows a very important rule: in C, arguments are passed by value. A function receives a copy of the variable, not the variable itself, so changing the parameter does not affect the caller's variable.
#include <stdio.h>
void print_line(int n) {
for (int i = 0; i < n; i++) {
printf("-");
}
printf("\n");
}
void try_to_change(int x) {
x = 100;
printf("Inside: x = %d\n", x);
}
int main(void) {
int x = 5;
print_line(12);
try_to_change(x);
printf("Outside: x = %d\n", x);
print_line(12);
return 0;
}------------ Inside: x = 100 Outside: x = 5 ------------
x inside the function is a copy: it became 100, while x in main stayed 5.You don't have to write every function yourself. The standard library's math.h header has ready-made math functions: sqrt (square root), pow (power), fabs (absolute value) and more. They take and return double values. On Linux you may need to add -lm at the end when compiling such a program.
#include <stdio.h>
#include <math.h>
int main(void) {
printf("%.2f\n", sqrt(16.0));
printf("%.0f\n", pow(2, 10));
printf("%.1f\n", fabs(-7.5));
return 0;
}4.00 1024 7.5
Recursion: a function that calls itself
A function can also call itself — this is called recursion. A recursive function has two parts: a base case that solves the problem immediately, and a recursive step that makes the problem a bit smaller and calls the function again. The classic example is the factorial: n! = n · (n − 1)!, with the base case 1! = 1.
#include <stdio.h>
long long factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
int main(void) {
for (int i = 1; i <= 5; i++) {
printf("%d! = %lld\n", i, factorial(i));
}
printf("20! = %lld\n", factorial(20));
return 0;
}1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 20! = 2432902008176640000
long long type (%lld) is used — 20! no longer fits in an int.Trace the call factorial(4) step by step.
Show solutionHide solution
factorial(3) = 3 · factorial(2)
factorial(2) = 2 · factorial(1)
factorial(1) = 1 — the base case, the calls stop.
Now the results travel back: 2 · 1 = 2, 3 · 2 = 6, 4 · 6 = 24.
Key points
- A function has a return type, a name, parameters and a body;
returngives back the result. - If a function is called before its definition, its prototype must appear at the top of the file.
- A function that returns nothing has the type
void. - In C, arguments are passed by value: the function works with a copy.
- A recursive function must have a base case, or the stack overflows.
Check yourself
10 questions. Every correct answer earns XP.