Functions in C
Organize code into reusable blocks! Functions let you write code once and use it many times. Learn to create, call, and pass data to functions.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Create your own functions
- ✓Pass data to functions with parameters
- ✓Return values from functions
- ✓Understand function declaration vs definition
01What is a Function?
Simple Definition
A function is like a recipe or a machine:
- •You give it some ingredients (inputs)
- •It does some work (processing)
- •It gives you back a result (output)
Real-World Analogy: A Coffee Machine
☕
INPUT
Coffee beans + Water
⚙️
PROCESS
Grind + Brew
OUTPUT
Hot Coffee
A function works the same way: takes inputs, processes them, and returns a result!
Why Do We Need Functions?
Imagine you need to calculate the area of a rectangle at 10 different places in your program. Without functions, you would write the same formula 10 times!
Without Functions (Bad)
// Same code repeated 3 times!
int area1 = 5 * 10;
printf("Area: %d\n", area1);
int area2 = 8 * 4;
printf("Area: %d\n", area2);
int area3 = 12 * 6;
printf("Area: %d\n", area3);
// Problems:
// - Code repetition
// - Hard to change formula
// - Easy to make mistakes✓With Functions (Good)
// Define once
int area(int width, int height) {
return width * height;
}
// Use many times!
printf("Area: %d\n", area(5, 10));
printf("Area: %d\n", area(8, 4));
printf("Area: %d\n", area(12, 6));
// Benefits:
// - Write once, use anywhere
// - Easy to change
// - No mistakes| Benefit | What It Means | Example |
|---|---|---|
| Reusability | Write code once, use it many times | Call add(5, 3) anywhere in your program |
| Modularity | Break big problems into small pieces | calculateTax(), calculateDiscount(), calculateTotal() |
| Readability | Code is easier to understand | isValidEmail() tells you what it checks |
| Easy to Fix | Fix bug in one place, fixed everywhere | Fix calculateArea() once, all areas are correct |
02How to Write a Function (Step by Step)
Every function has 4 parts. Let's learn each one:
The 4 Parts of a Function
int add(int a, int b) {
return a + b;
}
Let's Understand Each Part:
Return Type — What does the function give back?
This tells C what type of value the function will return (give back) after it finishes.
| Return Type | Meaning | Example |
|---|---|---|
| int | Returns an integer (whole number) | int add() returns 5 |
| float | Returns a decimal number | float getPI() returns 3.14 |
| char | Returns a character | char getGrade() returns 'A' |
| void | Returns nothing | void sayHello() just prints |
Function Name — What do we call it?
The name you use to call (use) the function. Choose names that describe what the function does!
✓Good Names
calculateArea
getMaximum
printMessage
isEven
Bad Names
func1
doStuff
x
aaa
Parameters — What inputs does it need?
Parameters are inputs that the function needs to do its job. They go inside the parentheses ().
int add(int a, int b) {
return a + b;
}
No parameters? Use empty parentheses: void sayHello() or void sayHello(void)
Body — What does the function do?
The body contains the actual code that runs when you call the function. It's enclosed in curly braces {}.
int add(int a, int b) {
int sum = a + b;
return sum;
}
| Part | Description | Example |
|---|---|---|
| Return Type | Data type of value returned | int, float, void, char* |
| Function Name | Identifier to call the function | add, calculateArea, main |
| Parameters | Input values (optional) | (int a, int b) |
| Body | Code to execute | {...} |
▶ Try it: Shows a complete function with all parts labeled.
1#include <stdio.h>23// Function definition with all parts4int add(int a, int b) { // int = return type5 // add = function name6 // (int a, int b) = parameters7 int sum = a + b; // Function body8 return sum; // Return statement9}1011int main() {12 int result = add(5, 3); // Function call13 printf("5 + 3 = %d\n", result);14 15 // Can call multiple times with different values16 printf("10 + 20 = %d\n", add(10, 20));17 printf("100 + 200 = %d\n", add(100, 200));18 19 return 0;20}5 + 3 = 8
10 + 20 = 30
100 + 200 = 300
03Declaration vs Definition (Very Important!)
The Big Question: What's the Difference?
In C, you can do two things with a function:
Declaration (Announce)
“Hey compiler, there WILL be a function called add that takes 2 integers and returns an integer.”
Just a promise — no actual code yet!
Definition (Create)
“Here is the actual code for the add function.”
The real implementation!
See the Difference:
Declaration (Prototype)
int add(int a, int b);
↑ Ends with semicolon ; (NO body!)
- ✓ Has return type, name, parameters
- ✓ Ends with semicolon
; - ✓ NO curly braces
{} - ✓ NO code inside
Definition
int add(int a, int b) {
return a + b;
}
↑ Has body with actual code!
- ✓ Has return type, name, parameters
- ✓ NO semicolon after
() - ✓ HAS curly braces
{} - ✓ HAS code inside
Why Do We Need Declarations?
Real-World Analogy: A Phone Directory
Imagine you're making a phone call. You need to know:
Phone Number
(Declaration)
→
Actual Person
(Definition)
The declaration is like the phone number in a directory — it tells you the number exists. The definition is the actual person who answers when you call!
When Do You Need a Declaration?
When you call a function BEFORE defining it
If your function is defined below main(), you need a declaration at the top
When using multiple files
Declarations go in header files (.h), definitions go in source files (.c)
▶ Try it: Shows the difference between declaration (prototype) and definition.
1#include <stdio.h>23// ======= FUNCTION DECLARATION (Prototype) =======4// Tells compiler: "This function exists, takes 2 ints, returns int"5// Note: Ends with semicolon, no body6int multiply(int a, int b); // Parameter names optional: int multiply(int, int);78// ======= MAIN FUNCTION =======9int main() {10 // We can call multiply() here even though11 // its definition is BELOW main()12 int result = multiply(6, 7);13 printf("6 × 7 = %d\n", result);14 15 return 0;16}1718// ======= FUNCTION DEFINITION =======19// Provides the actual implementation20// Note: No semicolon, has body with { }21int multiply(int a, int b) {22 return a * b;23}6 × 7 = 42
What Happens Without Declaration?
If you call a function before it's declared/defined, the compiler may assume it returns int and take any arguments. This causes bugs and warnings!
04Function Prototype & Signature Explained
What's the Difference?
These two terms sound similar but mean slightly different things. Let's understand them:
Prototype
The complete declaration of a function including:
- • Return type
- • Function name
- • Parameter list
- • Semicolon at the end
int add(int a, int b);
Signature
The unique identity of a function (like a fingerprint):
- • Function name
- • Parameter types only
- • (NOT the return type!)
add(int, int)
Remember: Prototype = Declaration
The words “prototype” and “declaration” mean the same thing for functions!
int add(int a, int b);
float divide(float x, float y);
void printHello(void);
✓Valid vs Invalid Prototypes
✓Valid Prototypes
int add(int a, int b);
→ With parameter names
int add(int, int);
→ Names are optional!
void sayHello(void);
→ No parameters
char* getName(void);
→ Returns pointer
Invalid Prototypes
int add(int a, int b)
→ Missing semicolon!
add(int a, int b);
→ Missing return type!
int add(a, b);
→ Missing data types!
int add();
→ Ambiguous (means any args)
▶ Try it: Demonstrates function prototypes with and without parameter names.
1#include <stdio.h>23// Prototypes (declarations) - both are valid4int add(int a, int b); // With parameter names (more readable)5int subtract(int, int); // Without names (still valid)6void greet(void); // void = no parameters7float average(int arr[], int size); // Array parameter89int main() {10 printf("add(10, 5) = %d\n", add(10, 5));11 printf("subtract(10, 5) = %d\n", subtract(10, 5));12 greet();13 14 int nums[] = {10, 20, 30, 40, 50};15 printf("Average: %.2f\n", average(nums, 5));16 17 return 0;18}1920// Definitions21int add(int a, int b) {22 return a + b;23}2425int subtract(int x, int y) { // Names can differ from prototype!26 return x - y;27}2829void greet(void) {30 printf("Hello from greet()!\n");31}3233float average(int arr[], int size) {34 int sum = 0;35 for (int i = 0; i < size; i++) {36 sum += arr[i];37 }38 return (float)sum / size;39}add(10, 5) = 15
subtract(10, 5) = 5
Hello from greet()!
Average: 30.00
054 Types of Functions (Based on Input/Output)
How to Categorize Functions?
Every function can be put into one of 4 categories based on:
The 4 Types:
No Input, No Output
void sayHello(void) {
printf("Hello!");
}
Use when: Just do something (print, beep, etc.)
No Input, With Output
int getNumber(void) {
return 42;
}
Use when: Get a value (current time, random number)
With Input, No Output
void printNum(int n) {
printf("%d", n);
}
Use when: Do something with given value (print it, save it)
With Input, With Output
int add(int a, int b) {
return a + b;
}
Use when: Calculate/transform values (most common type!)
Most Functions are Type 4!
In real programs, most functions take some input and return some output. This is the most useful pattern: result = function(input)
▶ Try it: Demonstrates all four types of functions.
1#include <stdio.h>23// Type 1: No parameters, No return value4void sayHello(void) {5 printf("Hello, World!\n");6 // No return statement (or just: return;)7}89// Type 2: No parameters, With return value10int getRandomNumber(void) {11 return 42; // Returns a value12}1314// Type 3: With parameters, No return value15void printNumber(int num) {16 printf("The number is: %d\n", num);17 // No return value18}1920// Type 4: With parameters, With return value21int add(int a, int b) {22 return a + b; // Takes input, returns output23}2425int main() {26 // Call each type27 sayHello(); // Type 128 29 int num = getRandomNumber(); // Type 230 printf("Random: %d\n", num);31 32 printNumber(100); // Type 333 34 int sum = add(5, 3); // Type 435 printf("Sum: %d\n", sum);36 37 return 0;38}Hello, World!
Random: 42
The number is: 100
Sum: 8
Library Functions vs User-Defined Functions
| Type | Description | Examples |
|---|---|---|
| Library Functions | Pre-built functions in C standard library | printf(), scanf(), strlen(), malloc() |
| User-Defined | Functions you create yourself | add(), calculateArea(), myFunction() |
06Parameters vs Arguments (Don't Confuse!)
What's the Difference?
These two words sound similar but mean different things:
Parameters (Placeholders)
Variables listed in the function definition. They are like empty boxes waiting to be filled.
int add(int a, int b) {
Arguments (Actual Values)
Actual values passed when calling the function. They fill the empty boxes.
int result = add(5, 3);
Visual: How Parameters Get Values
When you call:
C copies values into parameters:
Function uses these values:
Easy Way to Remember
Parameters = Placeholders (in definition)
Arguments = Actual values (in call)
▶ Try it: Shows the relationship between parameters and arguments.
1#include <stdio.h>23// Parameters: x and y are placeholders4// They receive copies of the argument values5void showValues(int x, int y) {6 printf("Parameter x = %d\n", x);7 printf("Parameter y = %d\n", y);8}910int main() {11 int a = 10, b = 20;12 13 // Arguments: actual values passed to function14 printf("Calling showValues(a, b):\n");15 showValues(a, b); // a and b are arguments16 17 printf("\nCalling showValues(100, 200):\n");18 showValues(100, 200); // Literal values as arguments19 20 printf("\nCalling showValues(a + 5, b * 2):\n");21 showValues(a + 5, b * 2); // Expressions as arguments22 23 return 0;24}Calling showValues(a, b):
Parameter x = 10
Parameter y = 20
Calling showValues(100, 200):
Parameter x = 100
Parameter y = 200
Calling showValues(a + 5, b * 2):
Parameter x = 15
Parameter y = 40
07Variable Scope: Where Can You Use a Variable?
What is Scope?
Scope is the area of your program where a variable can be used. Think of it like rooms in a house — some things belong to one room, others can be accessed from anywhere!
3 Types of Variable Scope:
Local Variables
Created INSIDE a function
void myFunction() {
int x = 10;
printf("%d", x);
}
- •Created when function is called
- •Destroyed when function ends
- •Only usable inside that function
- ✓Most common type!
Global Variables
Created OUTSIDE all functions
int count = 0;
void func1() {
count++;
}
void func2() {
count++;
}
- •Created when program starts
- •Lives until program ends
- •Accessible from ANY function
- Use sparingly! (harder to track)
Static Local Variables
Local but REMEMBERS its value
void counter() {
static int count = 0;
count++;
printf("%d", count);
}
- •Only accessible in that function
- •Keeps value between calls!
- •Initialized only ONCE
- ✓Best of both worlds!
| Type | Declared | Accessible | Lifetime |
|---|---|---|---|
| Local Variable | Inside a function/block | Only within that function/block | Created on call, destroyed on return |
| Global Variable | Outside all functions | From any function in the file | Entire program execution |
| Static Local | Inside function with static | Only within that function | Retains value between calls |
▶ Try it: Demonstrates local, global, and static variables.
1#include <stdio.h>23// ======= GLOBAL VARIABLE =======4// Declared outside all functions5// Accessible from any function6int globalCount = 0;78void incrementGlobal(void) {9 globalCount++; // Can access global variable10 printf("Global count: %d\n", globalCount);11}1213void demonstrateLocal(void) {14 // ======= LOCAL VARIABLE =======15 // Only exists inside this function16 int localVar = 10;17 printf("Local variable: %d\n", localVar);18 localVar++;19 // localVar is destroyed when function returns20}2122void demonstrateStatic(void) {23 // ======= STATIC LOCAL VARIABLE =======24 // Retains value between function calls25 static int callCount = 0; // Initialized only once26 callCount++;27 printf("Function called %d time(s)\n", callCount);28}2930int main() {31 printf("=== Global Variable ===\n");32 incrementGlobal(); // 133 incrementGlobal(); // 234 incrementGlobal(); // 335 36 printf("\n=== Local Variable ===\n");37 demonstrateLocal(); // Always prints 1038 demonstrateLocal(); // Always prints 10 (reinitialized)39 40 printf("\n=== Static Variable ===\n");41 demonstrateStatic(); // 142 demonstrateStatic(); // 243 demonstrateStatic(); // 344 45 return 0;46}=== Global Variable ===
Global count: 1
Global count: 2
Global count: 3
=== Local Variable ===
Local variable: 10
Local variable: 10
=== Static Variable ===
Function called 1 time(s)
Function called 2 time(s)
Function called 3 time(s)
Avoid Overusing Global Variables
Global variables can cause bugs because any function can modify them. Prefer passing values as parameters for cleaner, more maintainable code.
08Call by Value vs Call by Reference
The Big Question
When you pass a variable to a function, can the function change the original variable?
Call by Value: NO
Function gets a COPY (default in C)
Call by Reference: YES ✓
Function gets the ADDRESS (using pointers)
Real-World Analogy
Call by Value = Photocopy
Imagine giving someone a photocopy of a document. They can write on the photocopy, but your original document stays unchanged!
void tryChange(int x) {
x = 100;
}
Call by Reference = Home Address
Imagine giving someone your home address. They can come to your house and actually change things there!
void reallyChange(int *x) {
*x = 100;
}
Visual Comparison
| Feature | Call by Value | Call by Reference |
|---|---|---|
| What is passed? | Copy of the value | Memory address |
| Can modify original? | No | Yes ✓ |
| Syntax | func(x) | func(&x) |
| Parameter type | int x | int *x |
▶ Try it: Demonstrates the difference between call by value and call by reference.
1#include <stdio.h>23// Call by Value - receives COPY, cannot modify original4void tryToModify(int x) {5 printf(" Inside function: x = %d\n", x);6 x = 999; // Only modifies the copy!7 printf(" After change: x = %d\n", x);8}910// Call by Reference - receives ADDRESS, CAN modify original11void actuallyModify(int *x) {12 printf(" Inside function: *x = %d\n", *x);13 *x = 999; // Modifies the original!14 printf(" After change: *x = %d\n", *x);15}1617// Practical example: swap function18void swapByValue(int a, int b) {19 int temp = a;20 a = b;21 b = temp;22 // This doesn't work - only swaps copies!23}2425void swapByReference(int *a, int *b) {26 int temp = *a;27 *a = *b;28 *b = temp;29 // This works - modifies originals!30}3132int main() {33 int num = 10;34 35 printf("=== Call by Value ===\n");36 printf("Before: num = %d\n", num);37 tryToModify(num);38 printf("After: num = %d (unchanged!)\n\n", num);39 40 printf("=== Call by Reference ===\n");41 printf("Before: num = %d\n", num);42 actuallyModify(&num); // Pass address with &43 printf("After: num = %d (changed!)\n\n", num);44 45 // Swap example46 int a = 5, b = 10;47 printf("=== Swap Example ===\n");48 printf("Before swap: a = %d, b = %d\n", a, b);49 swapByReference(&a, &b);50 printf("After swap: a = %d, b = %d\n", a, b);51 52 return 0;53}=== Call by Value ===
Before: num = 10
Inside function: x = 10
After change: x = 999
After: num = 10 (unchanged!)
=== Call by Reference ===
Before: num = 10
Inside function: *x = 10
After change: *x = 999
After: num = 999 (changed!)
=== Swap Example ===
Before swap: a = 5, b = 10
After swap: a = 10, b = 5
09Passing Arrays to Functions
How Do Arrays Work with Functions?
Arrays in C are special! When you pass an array to a function, you're actually passing a pointer to the first element, not a copy of the entire array.
What Actually Happens
arr
= &arr[0]
Function receives pointer to first element, not a copy!
3 Ways to Write Array Parameters
Style 1: Array notation
void func(int arr[])
Most common, clear intent
Style 2: With size
void func(int arr[5])
Size is ignored by compiler!
Style 3: Pointer
void func(int *arr)
Exactly the same as Style 1
Important: Always Pass Size!
The function has no way to know the array size! Always pass the size as a separate parameter.
▶ Try it: Shows how to pass arrays to functions correctly.
1#include <stdio.h>23// Function to print array elements4// Must pass size separately - function can't know array size!5void printArray(int arr[], int size) {6 printf("Array: ");7 for (int i = 0; i < size; i++) {8 printf("%d ", arr[i]);9 }10 printf("\n");11}1213// Function to calculate sum14int sumArray(int arr[], int size) {15 int sum = 0;16 for (int i = 0; i < size; i++) {17 sum += arr[i];18 }19 return sum;20}2122// Arrays are passed by reference - modifications affect original!23void doubleElements(int arr[], int size) {24 for (int i = 0; i < size; i++) {25 arr[i] *= 2; // Modifies original array!26 }27}2829int main() {30 int numbers[] = {10, 20, 30, 40, 50};31 int size = sizeof(numbers) / sizeof(numbers[0]); // = 532 33 printf("Original:\n");34 printArray(numbers, size);35 36 printf("Sum = %d\n", sumArray(numbers, size));37 38 // This modifies the original array!39 doubleElements(numbers, size);40 41 printf("After doubling:\n");42 printArray(numbers, size);43 44 return 0;45}Original:
Array: 10 20 30 40 50
Sum = 150
After doubling:
Array: 20 40 60 80 100
Key Points
- • Arrays are always passed by reference (as pointer)
- • Functions can modify the original array
- • Always pass size as a separate parameter
- • Use
const int arr[]to prevent modification
11Inline Functions (C99)
What is an Inline Function?
An inline function is a hint to the compiler to insert the function's code directly at the call site instead of making a function call. This can make small functions faster!
How Inline Works
Normal Function Call
main() calls add() → Jump to add() code → Execute add() → Return to main() → Continue main()
Overhead from jumping
Inline Function
main() with add() code inserted → Execute add() code directly → Continue main() No jumping overhead!
Code is copied in place
1#include <stdio.h>23// Inline function - hint to compiler to insert code directly4// Best for small, frequently called functions5inline int square(int x) {6 return x * x;7}89inline int max(int a, int b) {10 return (a > b) ? a : b;11}1213int main() {14 // These calls may be replaced with actual code15 printf("5 squared = %d\n", square(5));16 printf("10 squared = %d\n", square(10));17 18 printf("Max of 7 and 12 = %d\n", max(7, 12));19 20 // In tight loops, inline can help performance21 int sum = 0;22 for (int i = 1; i <= 5; i++) {23 sum += square(i); // May be optimized to: sum += i * i24 }25 printf("Sum of squares (1-5) = %d\n", sum);26 27 return 0;28}5 squared = 25
10 squared = 100
Max of 7 and 12 = 12
Sum of squares (1-5) = 55
✓Good for Inline
- • Small functions (1-3 lines)
- • Frequently called functions
- • Simple math operations
- • Getters/setters
Not Good for Inline
- • Large functions (bloats code)
- • Recursive functions
- • Functions with loops
- • Rarely called functions
Remember
inline is just a suggestion to the compiler. Modern compilers often make their own inlining decisions based on optimization level.
12Modern C Features for Functions
🆕 New Features in C11 and C23
Modern C standards introduced new keywords and attributes to make functions safer and more expressive.
1. _Noreturn Functions (C11)
Some functions never return to the caller (like exit() or infinite loops). Use _Noreturn to tell the compiler.
1#include <stdio.h>2#include <stdlib.h>3#include <stdnoreturn.h> // For noreturn macro (C11)45// This function never returns - it always exits the program6noreturn void fatalError(const char *message) {7 printf("FATAL ERROR: %s\n", message);8 exit(1); // Program ends here9 // No return statement needed (or possible!)10}1112// Alternative: use _Noreturn keyword directly13_Noreturn void infiniteLoop(void) {14 while (1) {15 // Runs forever16 }17}1819int main() {20 int divisor = 0;21 22 if (divisor == 0) {23 fatalError("Cannot divide by zero!");24 // Compiler knows code below won't run25 }26 27 printf("This won't print if divisor is 0\n");28 return 0;29}2. [[nodiscard]] Attribute (C23)
Warns if a function's return value is ignored. Great for error codes!
1#include <stdio.h>2#include <stdlib.h>34// C23: Warn if return value is ignored5[[nodiscard]] int allocateMemory(int size) {6 // Returns 0 on success, -1 on failure7 if (size <= 0) return -1;8 return 0; // Success9}1011// With a message explaining why12[[nodiscard("Error must be handled!")]] 13int openFile(const char *name) {14 return 0; // Assume success for demo15}1617int main() {18 // Good: checking return value19 int result = allocateMemory(100);20 if (result != 0) {21 printf("Allocation failed!\n");22 }23 24 // Warning: ignoring return value25 // allocateMemory(50); // Compiler warning!26 27 return 0;28}3. Static Array Parameters (C99)
Tell the compiler the minimum array size expected:
1#include <stdio.h>23// static 10 means: array must have AT LEAST 10 elements4// Helps compiler catch bugs and optimize5void processArray(int arr[static 10]) {6 for (int i = 0; i < 10; i++) {7 printf("%d ", arr[i]);8 }9 printf("\n");10}1112int main() {13 int valid[15] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};14 processArray(valid); // OK: 15 >= 1015 16 // int tooSmall[5] = {1, 2, 3, 4, 5};17 // processArray(tooSmall); // May warn: 5 < 1018 19 return 0;20}| Feature | Version | Purpose |
|---|---|---|
| inline | C99 | Suggest code insertion at call site |
| _Noreturn / noreturn | C11 | Function never returns |
| [[nodiscard]] | C23 | Warn if return value ignored |
| static in array params | C99 | Specify minimum array size |
| _Generic | C11 | Type-generic function selection |
!Code Pitfalls: Common Mistakes & What to Watch For
These are the most common mistakes that trip up beginners. Study them carefully to avoid hours of debugging!
Missing return statement
Non-void functions must return a value on all paths.
// WRONG - missing returnint getMax(int a, int b) { if (a > b) { return a; } // What if a <= b? No return!}// CORRECTint getMax(int a, int b) { if (a > b) { return a; } return b; // All paths return}Calling function without prototype
Always declare functions before using them.
// WRONG - using function before declarationint main() { int x = add(5, 3); // Compiler doesn't know about add() return 0;}int add(int a, int b) { return a + b; }// CORRECT - declare firstint add(int a, int b); // Prototypeint main() { int x = add(5, 3); // Now compiler knows return 0;}int add(int a, int b) { return a + b; }Returning address of local variable
Local variables are destroyed when function returns. Their addresses become invalid.
// WRONG - returning pointer to localint* getNumber() { int num = 42; return # // num is destroyed after return!}// CORRECT - use static or mallocint* getNumber() { static int num = 42; // Static persists return #}Wrong number or type of arguments
Arguments must match parameter types and count.
int add(int a, int b) { return a + b; }// WRONGadd(5); // Missing argumentadd(5, 3, 2); // Too many argumentsadd(5.5, 3.2); // Type mismatch (implicit conversion)// CORRECTadd(5, 3); // Exactly 2 int argumentsInfinite recursion (no base case)
Recursion without a stopping condition causes stack overflow.
// WRONG - no base caseint factorial(int n) { return n * factorial(n - 1); // Never stops!}// CORRECT - has base caseint factorial(int n) { if (n <= 1) return 1; // Base case return n * factorial(n - 1);}Watch Out When Copying Code!
Why You Must Verify copied Functions!
Functions are where Code seems most helpful — but also makes subtle errors that cause hard-to-find bugs:
1. Forgetting Return Statements
Copied code might write a function that should return a value but misses the return on some code paths, returning garbage.
int max(int a, int b) { if (a > b) return a; // Mistake: what if a <= b? // Returns garbage!}2. Pass-by-Value Confusion
Copied code often generates a "swap" function that doesn't actually swap because it uses pass-by-value instead of pointers:
// copied - looks right, does nothing!void swap(int a, int b) { int temp = a; a = b; b = temp;} // Original variables unchanged!3. Returning Pointer to Local Variable
Copied code might return a pointer to a local variable, which is destroyed when the function ends — causing undefined behavior or crashes.
Verification Checklist: (1) Do all paths return a value? (2) Does it modify the original or a copy? (3) Does it return references to local data?
15Frequently Asked Questions
Q:What's the difference between a parameter and an argument?
A: Parameters are the placeholder names in the function definition: void greet(char* name) — here name is a parameter. Arguments are the actual values you pass when calling: greet("Alice") — "Alice" is the argument. Think: Parameters are the "slots," arguments are what fills them.
Q:Why do I need function prototypes (declarations)?
A: C compiles top-to-bottom. If you call a function before defining it, the compiler doesn't know it exists. Prototypes at the top tell the compiler "this function exists and takes these parameters" so you can define the actual code later. Without prototypes, you'd have to order functions precisely — prototypes give you flexibility.
Q:How do I return multiple values from a function?
A: C functions can only return one value directly. Options: (1) Return a struct containing multiple values, (2) Use pointer parameters to "output" values: void getMinMax(int arr[], int *min, int *max), (3) Return an array (via pointer). Option 2 is most common in C.
Q:What does void mean for functions?
A: void means "nothing." As a return type, void printHello() returns nothing — you can't assign its result. As parameters, int getRandom(void) means it takes no inputs. Note:int f() vs int f(void) differ in C — () means "unspecified parameters,"(void) means "definitely no parameters."
Q:How do I pass an array to a function?
A: Arrays "decay" to pointers when passed, sovoid process(int arr[]) andvoid process(int *arr) are equivalent. Important: You must pass the size separately: void process(int arr[], int size) because the function has no way to know the array length otherwise (sizeofgives pointer size, not array size inside functions).
Q:What's the difference between local and global variables?
A: Local variables exist only inside their function — created when the function runs, destroyed when it returns.Global variables are declared outside all functions and exist for the program's lifetime. While global variables are accessible everywhere, they make code harder to debug and maintain. Best practice: use local variables and pass values as parameters.
Q:When should I use recursion vs loops?
A: Use recursion when the problem is naturally recursive (tree traversal, divide-and-conquer algorithms, mathematical definitions like factorial). Use loops when performance matters — recursion has overhead from function calls and can cause stack overflow for deep recursion. Most recursion can be converted to loops, but some problems are much cleaner with recursion.
16Summary
Key Takeaways
- •Function: Reusable block of code
- •Declaration: Prototype with semicolon
- •Definition: Actual code with body
- •Parameters: Placeholders in definition
- •Arguments: Values passed in call
- •Local scope: Inside function only
- •Global scope: Accessible everywhere
- •Call by value: Passes copy (default)
- •Call by reference: Passes address
- •Recursion: Function calls itself
- •Inline: Hint to insert code directly
- •Function pointer: Store function address
Quick Reference
Basic Function
int add(int a, int b) {
return a + b;
}Void Function
void sayHello(void) {
printf("Hello!");
}Prototype
// Declaration int add(int, int); // Call later...
Pass by Reference
void swap(int *a, int *b) {
int temp = *a;
*a = *b; *b = temp;
}Recursion
int fact(int n) {
if (n <= 1) return 1;
return n * fact(n-1);
}Function Pointer
int (*ptr)(int, int); ptr = add; ptr(5, 3); // = 8
What's Next?
Now that you understand functions, you're ready to learn about:
- →Arrays: Store multiple values of the same type
- →Strings: Work with text in C
- →Pointers: Deep dive into memory addresses
- →Structures: Create custom data types
Test Your Knowledge
Related Tutorials
Recursion in C
Functions that call themselves! Learn this powerful technique, understand how it uses the stack, and know when to use it.
Command Line Arguments in C
Learn to pass data to your programs when running them! Master argc and argv, parse command line flags, and build powerful CLI tools.
Variadic Functions (va_list)
Create functions that accept a variable number of arguments like printf! Master va_list, va_start, va_arg, va_end, and va_copy to build flexible, reusable functions.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!