Functions
A function is a named block of code that does one job. Functions let you reuse code, give names to steps, and break a big program into small pieces you can understand and test one at a time. Every C program is built from them, starting with main.
Defining and calling
#include <stdio.h> void print_divider(void) { printf("----------------\n"); } int main(void) { print_divider(); printf("Monthly report\n"); print_divider(); return 0; }
---------------- Monthly report ----------------
A definition has a return type (void means it returns nothing), a name, a parameter list in parentheses, and a body. Calling it runs the body, then returns to where you called from.
Parameters and return values
#include <stdio.h> double area_of_rectangle(double width, double height) { return width * height; } int main(void) { double kitchen = area_of_rectangle(4.2, 3.0); double hall = area_of_rectangle(6.0, 1.2); printf("Kitchen %.2f m2, hall %.2f m2, total %.2f m2\n", kitchen, hall, kitchen + hall); return 0; }
Kitchen 12.60 m2, hall 7.20 m2, total 19.80 m2
width and height are parameters; 4.2 and 3.0 are the arguments passed in. return sends a value back and ends the function immediately.
Declaring before use: prototypes
The compiler reads top to bottom, so a function must be declared before it's called. If you'd like main first, put a prototype — the function's header followed by a semicolon — above it:
#include <stdio.h> int square(int n); // prototype void greet(const char *name); int main(void) { greet("Ada"); printf("7 squared is %d\n", square(7)); return 0; } int square(int n) { return n * n; } void greet(const char *name) { printf("Hello, %s!\n", name); }
Hello, Ada! 7 squared is 49
Prototypes are also what header files contain (lesson 52). Calling a function that hasn't been declared at all is an error in modern C:
#include <stdio.h> int main(void) { printf("%d\n", cube(3)); return 0; } int cube(int n) { return n * n * n; }
main.c:4:20: error: call to undeclared function 'cube'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
(void) means "no parameters"
Write int main(void) and void print_divider(void), not empty parentheses. In C17 and earlier, () in a declaration means "parameters not specified", which turns off argument checking. (C23 finally makes () mean the same as (void).)
Returning early
#include <stdio.h> const char *describe_temperature(double celsius) { if (celsius < 0) return "freezing"; if (celsius < 15) return "cold"; if (celsius < 25) return "mild"; return "hot"; } int main(void) { double temps[] = { -3, 9, 18, 31 }; for (int i = 0; i < 4; i++) { printf("%5.1f: %s\n", temps[i], describe_temperature(temps[i])); } return 0; }
-3.0: freezing 9.0: cold 18.0: mild 31.0: hot
A function with a non-void return type must return a value on every path. Falling off the end without one is a bug that -Wall reports.
Designing good functions
- One job each. If you need "and" to describe it, consider splitting it.
- Name it after what it does:
count_vowels,is_valid_email,print_invoice. Functions answering yes/no questions often start withis_orhas_and returnbool. - Keep them short — a screenful at most is a good guide.
- Prefer parameters and return values over global variables, so each function's inputs and outputs are visible.
Try it yourself
Write is_prime returning bool, and use it to count the primes below 100.
25 primes below 100