Chapter 2 — Functions
Splitting a program into named, reusable pieces. Parameters, return values, recursion, and `static`.
What you'll learn
- 1Define and call functions with parameters and return value.
- 2Understand pass-by-value vs pass-by-pointer.
- 3Use recursion for problems that naturally divide.
- 4Use `static` for internal helpers and persistent locals.
Core Concepts
1) Definition vs declaration (prototype)
// prototype (declaration) — usually in a header
int add(int a, int b);
// definition — usually in a .c file
int add(int a, int b) {
return a + b;
}Functions used before they're defined need a **prototype** above.
2) Pass-by-value
void noop(int x) { x = 100; }
int n = 5;
noop(n);
printf("%d\n", n); // still 5 — caller untouchedC copies arguments. To mutate the caller's variable, pass a **pointer**.
3) Return types
int sum(int a, int b) { return a + b; }
double avg(int a, int b) { return (a + b) / 2.0; }
void print(const char *s) { printf("%s\n", s); } // returns nothing4) Recursion
int fact(int n) {
if (n <= 1) return 1;
return n * fact(n - 1);
}Always have a **base case**, otherwise you stack-overflow.
5) `static`
| Use | Effect |
|---|---|
| `static` on file-scope function | Visible only inside this `.c` file (private) |
| `static` on local variable | Keeps value between calls (initialized once) |
Examples
Example 1 — `ex01_basic.c`: simple add
int add(int a, int b) {
return a + b;
}
int main(void) {
printf("%d\n", add(2, 3));
return 0;
}**Output**
5Key: declare first or define before use; otherwise `-Wall` warns.
Example 2 — `ex02_recursion.c`: factorial
int fact(int n) {
if (n <= 1) return 1;
return n * fact(n - 1);
}
printf("%d\n", fact(5));**Output**
120Key: base case (`n <= 1`) prevents infinite recursion.
Example 3 — `ex03_array_param.c`: array as parameter (decays)
int sum(int *a, int n) {
int s = 0;
for (int i = 0; i < n; i++) s += a[i];
return s;
}
int a[] = {1, 2, 3, 4};
printf("%d\n", sum(a, 4));**Output**
10Key: an array parameter is really a pointer — you must also pass the length.
Example 4 — `ex04_static.c`: per-call counter
void hit(void) {
static int count = 0;
count++;
printf("called %d times\n", count);
}
hit(); hit(); hit();**Output**
called 1 times
called 2 times
called 3 timesKey: `static` makes the local survive between calls, initialized once.
Common mistakes
- **No prototype** — implicit declaration warning, may pick wrong types.
- **Forgetting `return`** in non-void — undefined return value.
- **Returning a pointer to a local** — local goes out of scope; the pointer dangles.
- **No base case** — infinite recursion → stack overflow.
Recap
- Prototypes go above first use; definitions live wherever.
- C is pass-by-value; pass pointers to mutate the caller's data.
- Recursion needs a base case.
- `static` controls visibility and lifetime.
Try it
cd src
gcc -std=c11 -Wall -o ex01 ex01_basic.c && ./ex01
gcc -std=c11 -Wall -o ex02 ex02_recursion.c && ./ex02
gcc -std=c11 -Wall -o ex03 ex03_array_param.c && ./ex03
gcc -std=c11 -Wall -o ex04 ex04_static.c && ./ex04💻 Examples
Compilable, runnable examples — see the output yourself.
#include <stdio.h>
int add(int a, int b);
int max(int a, int b);
void print_line(void);
int main(void) {
print_line();
printf("add(3, 4) = %d\n", add(3, 4));
printf("max(7, 2) = %d\n", max(7, 2));
print_line();
return 0;
}
int add(int a, int b) { return a + b; }
int max(int a, int b) { return a > b ? a : b; }
void print_line(void) { printf("--------------------\n"); }
5#include <stdio.h>
long long factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
long long fib(int n) {
if (n < 2) return n;
return fib(n - 1) + fib(n - 2);
}
int main(void) {
for (int i = 0; i <= 10; i++) {
printf("%2d! = %lld, fib(%2d) = %lld\n",
i, factorial(i), i, fib(i));
}
return 0;
}
120#include <stdio.h>
/* */
int sum(const int arr[], int n) {
int s = 0;
for (int i = 0; i < n; i++) s += arr[i];
return s;
}
double average(const int arr[], int n) {
return (double)sum(arr, n) / n;
}
int main(void) {
int data[] = {10, 20, 30, 40, 50};
int n = (int)(sizeof(data) / sizeof(data[0]));
printf("sum: %d\n", sum(data, n));
printf("mean: %.2f\n", average(data, n));
return 0;
}
10#include <stdio.h>
int counter(void) {
static int count = 0; /* */
count++;
return count;
}
int main(void) {
for (int i = 0; i < 5; i++) {
printf(" %d -> %d\n", i + 1, counter());
}
return 0;
}
called 1 times
called 2 times
called 3 times📝 Exercises
Try them yourself first, then open the solution to compare.
Problem 1 (hw01.c)
Goal: Write recursive `int fib(int n)` and print `fib(0..10)`.
- Filename: hw01.c
▶Toggle solution
#include <stdio.h>
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
int main(void) {
int a, b;
printf("Two ints: ");
scanf("%d %d", &a, &b);
printf("GCD(%d, %d) = %d\n", a, b, gcd(a, b));
return 0;
}
Problem 2 (hw02.c)
Goal: Write `int max(const int *a, int n)` and demonstrate.
- Filename: hw02.c
▶Toggle solution
#include <stdio.h>
int find_max_index(const int *arr, int n) {
int idx = 0;
for (int i = 1; i < n; i++)
if (arr[i] > arr[idx]) idx = i;
return idx;
}
int main(void) {
int arr[] = {3, 7, 2, 8, 5, 8, 1};
int n = (int)(sizeof(arr) / sizeof(arr[0]));
int idx = find_max_index(arr, n);
printf("max %d is at index %d.\n", arr[idx], idx);
return 0;
}
Problem 3 (hw03.c)
Goal: Write `double mean(const int *a, int n)` and `double stddev(const int *a, int n, double m)`.
- Filename: hw03.c
▶Toggle solution
#include <stdio.h>
void printBinary(unsigned int n) {
if (n > 1) printBinary(n / 2);
putchar('0' + (n % 2));
}
int main(void) {
unsigned int n;
printf("Positive int: ");
scanf("%u", &n);
printBinary(n);
putchar('\n');
return 0;
}
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗