🧩 Functions in C

Functions are one of the most important building blocks of C programming. They allow us to divide a large program into smaller, meaningful and reusable pieces of code.

Core idea:

A function is a named block of code designed to perform a particular task. Instead of writing the same logic repeatedly, we can place it inside a function and call that function whenever required.

11.1 What Is a Function?

A function is a block of statements that performs a specific operation. It can receive input through parameters and can optionally return a result.

#include <stdio.h>

void greet(void)
{
    printf("Hello, CodeBhavya!\n");
}

int main(void)
{
    greet();

    return 0;
}

Here, greet() is a user-defined function. When greet() is called, the statements inside its body execute.

Function name

greet

Return type

void

Parameters

void — no parameters

Function body

The statements inside { }

11.2 Why Do We Need Functions?

Imagine a program that contains 2,000 lines of code. If all of those statements are written inside main(), the program becomes difficult to read, test and maintain.

Functions allow us to divide the program according to responsibilities.

Without functions:
main()
{
    input code
    calculation code
    validation code
    display code
    another calculation
    another validation
    another display
}
With functions:
main()
{
    readData();
    calculateResult();
    validateResult();
    displayResult();
}
Reusability

Write logic once and call it multiple times.

Readability

Function names explain what different parts of a program do.

Testing

Individual functions can be tested separately.

Maintenance

Changes can often be isolated to one function.

11.3 Anatomy of a Function

return_type function_name(parameter_list)
{
    // function body
    statements;

    return value;
}

A function can be understood through four major parts:

Part Meaning Example
Return type Type of value returned by the function int
Function name Name used to call the function add
Parameters Inputs received by the function int a, int b
Function body Statements executed when called { ... }

11.4 Function Declaration

A function declaration tells the compiler about a function before the function is used.

int add(int a, int b);

This tells the compiler that a function named add:

  • returns an int
  • expects two int parameters
  • will be defined somewhere in the program
Remember:

A function declaration is also commonly called a function prototype.

11.5 Function Definition

The function definition contains the actual implementation.

int add(int a, int b)
{
    return a + b;
}

The definition tells the compiler what the function actually does.

Declaration vs Definition
Declaration Definition
Tells what the function looks like Contains the implementation
Usually ends with ; Contains a function body
int add(int, int); int add(int a, int b) { ... }

11.6 Calling a Function

A function does not execute merely because it has been defined. It executes when it is called.

#include <stdio.h>

void message(void)
{
    printf("Welcome to C Programming!\n");
}

int main(void)
{
    message();

    return 0;
}

The statement:

message();

is the function call.

Program flow

main()
   |
   | calls
   v
message()
   |
   | executes printf()
   v
returns to main()
   |
   v
return 0

11.7 Parameters and Arguments

Functions can receive data from the caller. The variables listed in the function definition are called parameters. The actual values supplied during the call are called arguments.

int add(int a, int b)
{
    return a + b;
}

int result = add(10, 20);
Term Example Meaning
Parameter int a Variable receiving a value
Parameter int b Variable receiving a value
Argument 10 Actual value supplied by caller
Argument 20 Actual value supplied by caller

11.8 Returning a Value

A function can calculate a result and send that result back to its caller using the return statement.

int square(int n)
{
    return n * n;
}

int main(void)
{
    int result;

    result = square(5);

    printf("%d\n", result);

    return 0;
}

Execution:

square(5)
    |
    | n = 5
    |
    | 5 * 5
    v
return 25
    |
    v
result = 25
Important:

The value returned by a function can be stored in a variable, printed, used in another expression, or passed to another function.

11.9 Functions That Return Nothing — void

If a function does not return a value, its return type can be void.

void display(void)
{
    printf("Hello!\n");
}

The first void means the function returns no value. The second void means it accepts no parameters.

void display(void);
Do not confuse these:
Declaration Meaning
void display(void); No return value and no parameters
void display(int n); No return value, one integer parameter
int display(void); Returns an integer, no parameters

11.10 Functions with Multiple Parameters

A function can receive multiple parameters.

int multiply(int a, int b, int c)
{
    return a * b * c;
}

int main(void)
{
    int result = multiply(2, 3, 4);

    printf("%d\n", result);

    return 0;
}

The values are matched with parameters according to their position:

multiply(2, 3, 4)

a = 2
b = 3
c = 4
Important:

The number, order and compatible types of arguments should match the function's parameter list.

11.11 Why Do We Need a Function Prototype?

Suppose the function is defined after main(). The compiler needs to know about the function before encountering the call.

#include <stdio.h>

int add(int a, int b);

int main(void)
{
    int result = add(10, 20);

    printf("%d\n", result);

    return 0;
}

int add(int a, int b)
{
    return a + b;
}

The prototype:

int add(int a, int b);

provides the necessary information before the call.

Prototype
    |
    v
Compiler knows function signature
    |
    v
main() calls add()
    |
    v
add() definition appears later
    |
    v
Function executes

11.12 Defining a Function Before main()

A function can also be completely defined before main(). In that case, the compiler has already seen the definition when it encounters the call.

#include <stdio.h>

int add(int a, int b)
{
    return a + b;
}

int main(void)
{
    printf("%d\n", add(5, 7));

    return 0;
}
Style 1

Prototype first, definition later.

Style 2

Definition first, then main().

11.13 Library Functions vs User-Defined Functions

Library Function User-Defined Function
Provided by C libraries Created by the programmer
printf() calculateTotal()
scanf() findMaximum()
strlen() isPrime()

For example, printf() is a library function provided through the standard I/O facilities, while add() in the following program is user-defined.

int add(int a, int b)
{
    return a + b;
}

11.14 C Uses Pass-by-Value

C passes function arguments by value. That means the function receives a value for its parameter. Changing that parameter does not directly change the caller's ordinary variable.

#include <stdio.h>

void change(int x)
{
    x = 100;
}

int main(void)
{
    int n = 10;

    change(n);

    printf("%d\n", n);

    return 0;
}

Output:

10
main()

n = 10
 |
 | value copied
 v
change()

x = 10
 |
 | x = 100
 v
x = 100

Back in main:

n is still 10
Important:

C does not have a separate "call by reference" parameter mechanism like some languages. C programs commonly achieve modification of caller data by passing addresses through pointers.

11.15 Local Variables Inside Functions

A variable declared inside a function normally has block scope and can be accessed only within the appropriate block.

void calculate(void)
{
    int total = 50;

    printf("%d\n", total);
}

The variable total is local to the function.

Common mistake:
void calculate(void)
{
    int total = 50;
}

int main(void)
{
    printf("%d", total);   /* Error */
}

total is not visible in main().

11.16 Functions and Global Variables

A variable defined outside functions can have file scope and may be accessible to functions in the same source file according to its declaration and linkage.

#include <stdio.h>

int count = 10;

void display(void)
{
    printf("%d\n", count);
}

int main(void)
{
    display();

    return 0;
}
Important design note:

Global variables can be useful in specific situations, but excessive use of global mutable state can make programs harder to understand and test. Prefer passing required data through function parameters when practical.

11.17 Passing an Array to a Function

Arrays are frequently processed using functions. When an array is passed to a function, the parameter is adjusted to a pointer to its first element.

#include <stdio.h>

void display(int arr[], int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
}

int main(void)
{
    int numbers[] = {10, 20, 30, 40};

    display(numbers, 4);

    return 0;
}
Why pass the size separately?

Inside the function, the parameter arr is not a complete array object. Therefore sizeof(arr) inside the function does not give the original array size.

11.18 Passing Strings to Functions

A C string is stored in a character array ending with the null character '\0'. A string can be passed to a function using a character pointer or an array parameter.

#include <stdio.h>

void displayString(const char text[])
{
    printf("%s\n", text);
}

int main(void)
{
    char name[] = "CodeBhavya";

    displayString(name);

    return 0;
}

The const qualifier communicates that the function does not intend to modify the characters through that parameter.

11.19 Functions and Pointers — Preview

Pointers allow a function to work with the address of an object. This is how a function can modify a variable belonging to its caller.

#include <stdio.h>

void change(int *x)
{
    *x = 100;
}

int main(void)
{
    int n = 10;

    change(&n);

    printf("%d\n", n);

    return 0;
}

Here:

&n   → address of n
*x   → value stored at that address
Do not worry about pointers yet.

Pointers will be studied in detail in the dedicated Pointers topic. For now, remember that passing an address gives a function access to the same object.

11.20 Recursion

Recursion occurs when a function calls itself.

void countDown(int n)
{
    if (n == 0)
    {
        return;
    }

    printf("%d\n", n);

    countDown(n - 1);
}

A recursive function normally needs two important parts:

Base case

The condition that stops recursion.

Recursive case

The part that calls the function again.

Without a proper base case:

The recursive calls may continue until the program exhausts available stack space, resulting in undefined behavior or abnormal termination.

11.21 Program Tracing — Recursive Function

Consider:

void countDown(int n)
{
    if (n == 0)
        return;

    printf("%d ", n);

    countDown(n - 1);
}

Suppose:

countDown(3);

The execution can be visualized as:

countDown(3)
    |
    | print 3
    v
countDown(2)
    |
    | print 2
    v
countDown(1)
    |
    | print 1
    v
countDown(0)
    |
    | base case
    v
return

Output:
3 2 1
Important tracing idea

When a function calls another function, the current function's execution is paused until the called function returns. For recursion, this creates a chain of active function calls.

11.22 Function Calls and the Call Stack

When a function is called, the program needs to keep track of the function's execution state, parameters and local information. This is commonly represented using the call stack.

main()
  |
  +--> calculate()
          |
          +--> square()
                  |
                  +--> return
          |
          +--> return
  |
  +--> return
TOP
┌──────────────────────┐
│ square()             │
├──────────────────────┤
│ calculate()          │
├──────────────────────┤
│ main()               │
└──────────────────────┘
BOTTOM

When square() returns, its active call is removed and execution continues in calculate().

11.23 One Function Can Call Another Function

#include <stdio.h>

int square(int n)
{
    return n * n;
}

int doubleValue(int n)
{
    return 2 * n;
}

int main(void)
{
    int value = square(doubleValue(3));

    printf("%d\n", value);

    return 0;
}

Trace the calls from the inside:

doubleValue(3)
    ↓
6

square(6)
    ↓
36

value = 36
Tracing tip

For nested function calls, identify which function must produce a value first.

Placement tip

Draw the call chain when the expression looks complicated.

11.24 Designing Good Functions

A good function generally has a clear responsibility.

Less Clear Better Decomposition
One huge main() readInput()
Mixed calculation and display calculateTotal()
Repeated validation logic isValid()
Repeated searching logic findMaximum()
Think in responsibilities:
Input
  ↓
Validation
  ↓
Calculation
  ↓
Output

Each responsibility can potentially become a separate function.

11.25 Common Mistakes

1. Calling a function with the wrong number of arguments

int add(int a, int b);

add(10);       /* Wrong */
add(10, 20);   /* Correct */

2. Forgetting the return statement

int square(int n)
{
    n * n;      /* Does not return the result */
}

Correct:

int square(int n)
{
    return n * n;
}

3. Returning a value from a void function

void display(void)
{
    return 10;      /* Wrong */
}

4. Using a local variable outside its scope

void test(void)
{
    int x = 10;
}

int main(void)
{
    printf("%d", x);    /* Wrong */
}

5. Infinite recursion

void test(void)
{
    test();
}

There is no terminating condition.

6. Modifying a variable incorrectly through a value parameter

void change(int x)
{
    x = 100;
}

This does not modify the caller's ordinary variable.

11.26 Common Confusions

Function declaration vs function call

int add(int, int);     /* declaration */

add(10, 20);           /* call */

Parameter vs argument

int add(int a, int b)
{
    return a + b;
}

add(5, 7);

a and b are parameters. 5 and 7 are arguments.

Return value vs printing

int square(int n)
{
    return n * n;
}

Returning a value and printing a value are different operations.

void parameter list

void display(void)

This explicitly means that the function accepts no parameters.

11.27 Complete Program Analysis

#include <stdio.h>

int calculateSquare(int n);

int main(void)
{
    int number;
    int result;

    printf("Enter a number: ");
    scanf("%d", &number);

    result = calculateSquare(number);

    printf("Square = %d\n", result);

    return 0;
}

int calculateSquare(int n)
{
    return n * n;
}

Execution flow

1. Program starts
       ↓
2. main() begins
       ↓
3. number is declared
       ↓
4. Input is read
       ↓
5. calculateSquare(number) is called
       ↓
6. value is copied into n
       ↓
7. n * n is calculated
       ↓
8. result is returned
       ↓
9. result receives returned value
       ↓
10. printf() displays result
       ↓
11. return 0
       ↓
12. Program ends

11.28 Four Common Function Forms

A useful beginner classification is based on whether a function receives arguments and whether it returns a value.

Type Example
No arguments, no return value void display(void)
Arguments, no return value void display(int n)
No arguments, returns value int getNumber(void)
Arguments and returns value int add(int a, int b)
Placement memory trick:

Ask two questions:

  1. Does the function receive data?
  2. Does the function return data?

Those two answers help identify the function form.

11.29 Important Interview Point: Array Parameter

Consider:

void display(int arr[])

For a function parameter, an array parameter is adjusted to a pointer parameter. Therefore, these forms are equivalent for parameter purposes:

void display(int arr[]);
void display(int *arr);

The array's size is therefore commonly passed separately:

void display(int arr[], int size)
Do not say:

"An array is completely copied when passed to a function."

Better explanation:

For a function parameter, an array parameter is adjusted to a pointer to its first element, so the function can access the original array elements.

11.30 Quick Revision

Function

Reusable block of code for a particular task.

Prototype

Declares a function before its use.

Parameter

Variable listed in a function definition.

Argument

Actual value supplied during a call.

Return

Sends a value back to the caller.

void

Represents no value in relevant function contexts.

Recursion

A function calling itself.

Call by value

C passes argument values to parameters.

🧠 Test Your Understanding

1 What is the difference between a function declaration and definition?
A declaration tells the compiler about the function's name, return type and parameters. A definition contains the actual function body and implementation.
2 What is the difference between a parameter and an argument?
A parameter is a variable in the function definition. An argument is the actual value supplied during the function call.
3 Does C pass ordinary arguments by reference?
No. C passes arguments by value. A function can modify caller data by receiving an address through a pointer.
4 Why is the array size commonly passed separately to a function?
Because an array parameter is adjusted to a pointer to its first element. The function therefore does not automatically receive the original array's element count.
5 What are the two essential parts of a recursive function?
A recursive function normally needs a base case that stops recursion and a recursive case that makes progress toward that base case.

🎯 Interview Preparation

1. What is a function in C?

A function is a named block of code that performs a particular task. It may receive parameters and may return a value.

2. What is a function prototype?

A function prototype declares the function's return type, name and parameter types before the function is used.

3. What is call by value?

C passes argument values to function parameters. The parameter is therefore a separate object/value from the caller's ordinary variable.

4. How can a function modify a caller's variable?

By passing its address to the function and using a pointer parameter.

5. What is recursion?

Recursion occurs when a function directly or indirectly calls itself. A terminating condition is required.

6. Can a function return multiple values directly?

A function has one return value expression. Multiple pieces of information can be returned through pointers, structures, or other suitable designs.

7. Can a function return an array directly?

A function cannot return an array type directly. Other techniques such as returning a pointer to suitable storage or returning a structure can be used depending on the problem.

💼 Placement Tips

Tip 1 — Trace calls

For function-based questions, first identify the order in which functions are called.

Tip 2 — Check return values

Follow exactly where each returned value is stored or used.

Tip 3 — Watch scope

A local variable belongs to its appropriate block and cannot automatically be used elsewhere.

Tip 4 — Know value passing

Remember that C passes arguments by value.

Tip 5 — Recursion

Always identify the base case before tracing recursive calls.

Tip 6 — Arrays

Remember that an array parameter is adjusted to a pointer parameter.

✍️ PRACTICE

11.31 Function Practice Problems

Solve these problems using user-defined functions. Try the problem yourself before opening the solution.

Functions Practice Progress
5 Problems
Beginner Difficulty
C Language

Problem 1 — Add Two Numbers Using a Function

Not Started

Read two integers and create a function add() that returns their sum.

Create:
int add(int a, int b)
Then return a + b.

Your Program

Input

Expected Output

30
Score: 0
Tests: 0 / 1
Attempts: 0
Status: Not Started
Write your solution and check it.
#include <stdio.h>

int add(int a, int b)
{
    return a + b;
}

int main(void)
{
    int a, b;

    scanf("%d %d", &a, &b);

    printf("%d\n", add(a, b));

    return 0;
}

Problem 2 — Find the Larger Number

Not Started

Create a function maximum() that receives two integers and returns the larger value.

Use an if condition inside the function.

Your Program

Input

Expected Output

25
Score: 0
Tests: 0 / 1
Attempts: 0
Status: Not Started
Write your solution and check it.
#include <stdio.h>

int maximum(int a, int b)
{
    if (a > b)
        return a;

    return b;
}

int main(void)
{
    int a, b;

    scanf("%d %d", &a, &b);

    printf("%d\n", maximum(a, b));

    return 0;
}

Problem 3 — Check Even or Odd

Not Started

Create a function isEven() that returns 1 when the supplied integer is even and 0 otherwise.

Use the remainder operator:
n % 2

Your Program

Input

Expected Output

1
Score: 0
Tests: 0 / 1
Attempts: 0
Status: Not Started
Write your solution and check it.
#include <stdio.h>

int isEven(int n)
{
    return n % 2 == 0;
}

int main(void)
{
    int n;

    scanf("%d", &n);

    printf("%d\n", isEven(n));

    return 0;
}

Problem 4 — Calculate Square and Cube

Not Started

Create two functions: square() and cube(). Read one integer and print both results.

Both functions should return an integer result.

Your Program

Input

Expected Output

Square = 16
Cube = 64
Score: 0
Tests: 0 / 1
Attempts: 0
Status: Not Started
Write your solution and check it.
#include <stdio.h>

int square(int n)
{
    return n * n;
}

int cube(int n)
{
    return n * n * n;
}

int main(void)
{
    int n;

    scanf("%d", &n);

    printf("Square = %d\n", square(n));
    printf("Cube = %d\n", cube(n));

    return 0;
}

Problem 5 — Sum from 1 to N Using a Function

Not Started

Create a function sumToN() that receives a positive integer n and returns the sum of all integers from 1 through n.

Use a loop inside the function.
sum = 0;

for (...)
{
    sum += i;
}

Your Program

Input

Expected Output

55
Score: 0
Tests: 0 / 1
Attempts: 0
Status: Not Started
Write your solution and check it.
#include <stdio.h>

int sumToN(int n)
{
    int sum = 0;

    for (int i = 1; i <= n; i++)
    {
        sum += i;
    }

    return sum;
}

int main(void)
{
    int n;

    scanf("%d", &n);

    printf("%d\n", sumToN(n));

    return 0;
}
🚀 EXTRA PRACTICE

11.32 Challenge Yourself

Try these without looking at the solution:

  1. Write a function to find the minimum of three integers.
  2. Write a function that counts the number of digits in an integer.
  3. Write a function to calculate the factorial of a number.
  4. Write a recursive function to calculate factorial.
  5. Write a function that checks whether a number is prime.
  6. Write a function that reverses an integer.
  7. Write a function that calculates the sum of array elements.
  8. Write a function that finds the maximum element of an array.
  9. Write a function that counts vowels in a string.
  10. Write a function that checks whether a string is a palindrome.
Placement Challenge

Given an array of integers, create separate functions to calculate:

  • sum
  • average
  • maximum
  • minimum
  • number of even elements
  • number of odd elements

Keep main() responsible mainly for input, function calls and displaying results.

⭐ Key Takeaway

Functions divide a program into reusable units.

A function can receive data through parameters, perform an operation, and optionally return a result to its caller.

Input
  ↓
Function Call
  ↓
Parameters receive values
  ↓
Function executes
  ↓
Return value
  ↓
Caller continues

Mastering functions is essential before moving deeply into pointers, structures, dynamic memory and larger C programs.