Chapter 12Beginner

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.

20 min readUpdated 2024-12-16
functionsparametersargumentsreturnvoidfunction calldeclaration

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
BenefitWhat It MeansExample
πŸ”„ ReusabilityWrite code once, use it many timesCall add(5, 3) anywhere in your program
🧩 ModularityBreak big problems into small piecescalculateTax(), calculateDiscount(), calculateTotal()
πŸ“– ReadabilityCode is easier to understandisValidEmail() tells you what it checks
πŸ”§ Easy to FixFix bug in one place, fixed everywhereFix 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

1. Return Type2. Name(3. Parameters){4. Body}

int add(int a, int b) {

return a + b;

}

Let's Understand Each Part:

1

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 TypeMeaningExample
intReturns an integer (whole number)int add() returns 5
floatReturns a decimal numberfloat getPI() returns 3.14
charReturns a characterchar getGrade() returns 'A'
voidReturns nothingvoid sayHello() just prints
2

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

3

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)

4

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;

}

PartDescriptionExample
Return TypeData type of value returnedint, float, void, char*
Function NameIdentifier to call the functionadd, calculateArea, main
ParametersInput values (optional)(int a, int b)
BodyCode to execute{...}

πŸ“ This program shows a complete function with all parts labeled.

function_anatomy.c
C
1#include <stdio.h>
2
3// Function definition with all parts
4int add(int a, int b) { // int = return type
5 // add = function name
6 // (int a, int b) = parameters
7 int sum = a + b; // Function body
8 return sum; // Return statement
9}
10
11int main() {
12 int result = add(5, 3); // Function call
13 printf("5 + 3 = %d\n", result);
14
15 // Can call multiple times with different values
16 printf("10 + 20 = %d\n", add(10, 20));
17 printf("100 + 200 = %d\n", add(100, 200));
18
19 return 0;
20}
Output

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?

1.

When you call a function BEFORE defining it

If your function is defined below main(), you need a declaration at the top

2.

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.

declaration_vs_definition.c
C
1#include <stdio.h>
2
3// ======= FUNCTION DECLARATION (Prototype) =======
4// Tells compiler: "This function exists, takes 2 ints, returns int"
5// Note: Ends with semicolon, no body
6int multiply(int a, int b); // Parameter names optional: int multiply(int, int);
7
8// ======= MAIN FUNCTION =======
9int main() {
10 // We can call multiply() here even though
11 // its definition is BELOW main()
12 int result = multiply(6, 7);
13 printf("6 Γ— 7 = %d\n", result);
14
15 return 0;
16}
17
18// ======= FUNCTION DEFINITION =======
19// Provides the actual implementation
20// Note: No semicolon, has body with { }
21int multiply(int a, int b) {
22 return a * b;
23}
Output

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.

prototypes.c
C
1#include <stdio.h>
2
3// Prototypes (declarations) - both are valid
4int add(int a, int b); // With parameter names (more readable)
5int subtract(int, int); // Without names (still valid)
6void greet(void); // void = no parameters
7float average(int arr[], int size); // Array parameter
8
9int 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}
19
20// Definitions
21int add(int a, int b) {
22 return a + b;
23}
24
25int subtract(int x, int y) { // Names can differ from prototype!
26 return x - y;
27}
28
29void greet(void) {
30 printf("Hello from greet()!\n");
31}
32
33float 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}
Output

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:

πŸ“₯Does it take inputs? (Parameters)
πŸ“€Does it give back output? (Return value)

The 4 Types:

1

No Input, No Output

void sayHello(void) {

printf("Hello!");

}

Use when: Just do something (print, beep, etc.)

2

No Input, With Output

int getNumber(void) {

return 42;

}

Use when: Get a value (current time, random number)

3

With Input, No Output

void printNum(int n) {

printf("%d", n);

}

Use when: Do something with given value (print it, save it)

4

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.

function_types.c
C
1#include <stdio.h>
2
3// Type 1: No parameters, No return value
4void sayHello(void) {
5 printf("Hello, World!\n");
6 // No return statement (or just: return;)
7}
8
9// Type 2: No parameters, With return value
10int getRandomNumber(void) {
11 return 42; // Returns a value
12}
13
14// Type 3: With parameters, No return value
15void printNumber(int num) {
16 printf("The number is: %d\n", num);
17 // No return value
18}
19
20// Type 4: With parameters, With return value
21int add(int a, int b) {
22 return a + b; // Takes input, returns output
23}
24
25int main() {
26 // Call each type
27 sayHello(); // Type 1
28
29 int num = getRandomNumber(); // Type 2
30 printf("Random: %d\n", num);
31
32 printNumber(100); // Type 3
33
34 int sum = add(5, 3); // Type 4
35 printf("Sum: %d\n", sum);
36
37 return 0;
38}
Output

Hello, World!

Random: 42

The number is: 100

Sum: 8

Library Functions vs User-Defined Functions

TypeDescriptionExamples
Library FunctionsPre-built functions in C standard libraryprintf(), scanf(), strlen(), malloc()
User-DefinedFunctions you create yourselfadd(), 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:

add(5, 3);
↓

C copies values into parameters:

a = 5, b = 3
↓

Function uses these values:

return a + b;

πŸ’‘ Easy Way to Remember

Parameters = Placeholders (in definition)
Arguments = Actual values (in call)

πŸ“ This program shows the relationship between parameters and arguments.

params_args.c
C
1#include <stdio.h>
2
3// Parameters: x and y are placeholders
4// They receive copies of the argument values
5void showValues(int x, int y) {
6 printf("Parameter x = %d\n", x);
7 printf("Parameter y = %d\n", y);
8}
9
10int main() {
11 int a = 10, b = 20;
12
13 // Arguments: actual values passed to function
14 printf("Calling showValues(a, b):\n");
15 showValues(a, b); // a and b are arguments
16
17 printf("\nCalling showValues(100, 200):\n");
18 showValues(100, 200); // Literal values as arguments
19
20 printf("\nCalling showValues(a + 5, b * 2):\n");
21 showValues(a + 5, b * 2); // Expressions as arguments
22
23 return 0;
24}
Output

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:

1

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!
2

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)
3

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!
TypeDeclaredAccessibleLifetime
Local VariableInside a function/blockOnly within that function/blockCreated on call, destroyed on return
Global VariableOutside all functionsFrom any function in the fileEntire program execution
Static LocalInside function with staticOnly within that functionRetains value between calls

πŸ“ This program demonstrates local, global, and static variables.

scope.c
C
1#include <stdio.h>
2
3// ======= GLOBAL VARIABLE =======
4// Declared outside all functions
5// Accessible from any function
6int globalCount = 0;
7
8void incrementGlobal(void) {
9 globalCount++; // Can access global variable
10 printf("Global count: %d\n", globalCount);
11}
12
13void demonstrateLocal(void) {
14 // ======= LOCAL VARIABLE =======
15 // Only exists inside this function
16 int localVar = 10;
17 printf("Local variable: %d\n", localVar);
18 localVar++;
19 // localVar is destroyed when function returns
20}
21
22void demonstrateStatic(void) {
23 // ======= STATIC LOCAL VARIABLE =======
24 // Retains value between function calls
25 static int callCount = 0; // Initialized only once
26 callCount++;
27 printf("Function called %d time(s)\n", callCount);
28}
29
30int main() {
31 printf("=== Global Variable ===\n");
32 incrementGlobal(); // 1
33 incrementGlobal(); // 2
34 incrementGlobal(); // 3
35
36 printf("\n=== Local Variable ===\n");
37 demonstrateLocal(); // Always prints 10
38 demonstrateLocal(); // Always prints 10 (reinitialized)
39
40 printf("\n=== Static Variable ===\n");
41 demonstrateStatic(); // 1
42 demonstrateStatic(); // 2
43 demonstrateStatic(); // 3
44
45 return 0;
46}
Output

=== 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

FeatureCall by ValueCall by Reference
What is passed?Copy of the valueMemory address
Can modify original?No ❌Yes βœ“
Syntaxfunc(x)func(&x)
Parameter typeint xint *x

πŸ“ This program demonstrates the difference between call by value and call by reference.

call_by.c
C
1#include <stdio.h>
2
3// Call by Value - receives COPY, cannot modify original
4void 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}
9
10// Call by Reference - receives ADDRESS, CAN modify original
11void 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}
16
17// Practical example: swap function
18void swapByValue(int a, int b) {
19 int temp = a;
20 a = b;
21 b = temp;
22 // This doesn't work - only swaps copies!
23}
24
25void swapByReference(int *a, int *b) {
26 int temp = *a;
27 *a = *b;
28 *b = temp;
29 // This works - modifies originals!
30}
31
32int 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 example
46 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}
Output

=== 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.

main.c
C
// WRONG - missing return
int getMax(int a, int b) {
if (a > b) {
return a;
}
// What if a <= b? No return!
}
// CORRECT
int 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.

main.c
C
// WRONG - using function before declaration
int 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 first
int add(int a, int b); // Prototype
int 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.

main.c
C
// WRONG - returning pointer to local
int* getNumber() {
int num = 42;
return &num; // num is destroyed after return!
}
// CORRECT - use static or malloc
int* getNumber() {
static int num = 42; // Static persists
return &num;
}

❌ Wrong number or type of arguments

Arguments must match parameter types and count.

main.c
C
int add(int a, int b) { return a + b; }
// WRONG
add(5); // Missing argument
add(5, 3, 2); // Too many arguments
add(5.5, 3.2); // Type mismatch (implicit conversion)
// CORRECT
add(5, 3); // Exactly 2 int arguments

❌ Infinite recursion (no base case)

Recursion without a stopping condition causes stack overflow.

main.c
C
// WRONG - no base case
int factorial(int n) {
return n * factorial(n - 1); // Never stops!
}
// CORRECT - has base case
int 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!