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.
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 | {...} |
π This program 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)
π This program 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)
π This program 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)
π This program 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)
π This program 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 |
π This program 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 |
π This program 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
09Common Function Mistakes
β 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 argumentsβ Infinite 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);}10Summary
π― Key Takeaways
- β’Function: Reusable block of code with name, parameters, and return type
- β’Declaration: Tells compiler function exists (prototype with ;)
- β’Definition: Provides actual code (body with {})
- β’Parameters: Variables in function definition
- β’Arguments: Actual values passed in function call
- β’Local scope: Variables inside function (temporary)
- β’Global scope: Variables outside all functions (persistent)
- β’Call by value: Function gets copy (default in C)
- β’Call by reference: Use pointers to modify originals
12Next Steps
Now that you understand functions, learn about the static keyword for persistent variables!