Functions
Understand function declaration, parameters, return values, and recursion in C.
Function Declaration and Definition
A function in C is a self-contained block of code that performs a specific task. A function declaration, also called a prototype, tells the compiler about the function's name, return type, and parameters. The function definition provides the actual implementation. Declaring prototypes at the top of the file or in a header allows you to call functions before they are defined, which is important for organizing larger programs.
#include <stdio.h>
/* Function prototypes */
int add(int a, int b);
void greet(const char *name);
int main(void) {
int result = add(15, 27);
printf("15 + 27 = %d\n", result);
greet("Alice");
return 0;
}
/* Function definitions */
int add(int a, int b) {
return a + b;
}
void greet(const char *name) {
printf("Hello, %s! Welcome to C programming.\n", name);
}
Parameters and Arguments
C uses pass-by-value semantics, meaning function parameters receive copies of the arguments. Modifying a parameter inside a function does not affect the original variable in the caller. To modify the caller's variable you must pass a pointer to it instead. Arrays are an exception because when passed to a function they decay into a pointer to their first element, so changes to array elements inside the function are visible to the caller.
#include <stdio.h>
void tryToModify(int x) {
x = 999;
printf("Inside tryToModify: x = %d\n", x);
}
void actuallyModify(int *x) {
*x = 999;
printf("Inside actuallyModify: *x = %d\n", *x);
}
double average(const int arr[], int size) {
double sum = 0;
for (int i = 0; i < size; i++) {
sum += arr[i];
}
return sum / size;
}
int main(void) {
int value = 42;
tryToModify(value);
printf("After tryToModify: value = %d\n", value);
actuallyModify(&value);
printf("After actuallyModify: value = %d\n", value);
int scores[] = {85, 92, 78, 90, 88};
printf("Average: %.2f\n", average(scores, 5));
return 0;
}
Return Values
Functions can return a single value to the caller using the return statement. The return type is specified in the function declaration and must match the type of the value returned. A function declared with void returns no value. You can use the return value directly in expressions, assign it to a variable, or pass it as an argument to another function. Returning early from a function is a common pattern for handling error conditions.
#include <stdio.h>
int factorial(int n) {
if (n < 0) {
return -1; /* Error indicator */
}
int result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
int clamp(int value, int min, int max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
int main(void) {
printf("5! = %d\n", factorial(5));
printf("10! = %d\n", factorial(10));
printf("clamp(150, 0, 100) = %d\n", clamp(150, 0, 100));
printf("clamp(-20, 0, 100) = %d\n", clamp(-20, 0, 100));
printf("clamp(50, 0, 100) = %d\n", clamp(50, 0, 100));
return 0;
}
Recursion
Recursion occurs when a function calls itself to solve a smaller instance of the same problem. Every recursive function needs a base case that stops the recursion and a recursive case that reduces the problem size. Without a proper base case the function will recurse infinitely and crash with a stack overflow. Recursion is elegant for problems with natural recursive structure such as tree traversals, but iterative solutions are often more efficient in C due to limited stack space.
#include <stdio.h>
int fibonacci(int n) {
if (n <= 0) return 0;
if (n == 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
int power(int base, int exp) {
if (exp == 0) return 1;
return base * power(base, exp - 1);
}
void printBinary(unsigned int n) {
if (n > 1) {
printBinary(n / 2);
}
printf("%d", n % 2);
}
int main(void) {
printf("Fibonacci sequence: ");
for (int i = 0; i < 10; i++) {
printf("%d ", fibonacci(i));
}
printf("\n");
printf("2^10 = %d\n", power(2, 10));
printf("42 in binary: ");
printBinary(42);
printf("\n");
return 0;
}