Functions & Prototypes

C · Lesson 13 of 32 7 min read Updated

A function is a named block of code that does one job. You have been calling functions since your first program: printf is one, and main is one too. Now you will write your own.

Functions let you write a piece of logic once and use it many times, give it a clear name, and test it on its own. In this lesson you will define and call functions, declare them with prototypes, learn how C passes arguments, and use the maths library.

Defining and calling a function

A function definition has a return type, a name, a list of parameters in brackets and a body in braces.

C
#include <stdio.h>

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

int main(void)
{
    int side = 7;
    printf("Area of a %d m square plot: %d sq m\n", side, square(side));
    printf("Square of 12 is %d\n", square(12));
    return 0;
}
Output
Area of a 7 m square plot: 49 sq m
Square of 12 is 144

int square(int n) says: this function is called square, takes one int called n, and gives back an int. The values you pass when calling, such as side or 12, are the arguments. Each argument is copied into the matching parameter, and return sends the result back to the caller, where the call square(side) is replaced by that value.

Functions that return nothing

A function that only performs an action, such as printing, has the return type void. It may use a bare return; to finish early, or simply reach its closing brace. A function with no parameters lists void inside the brackets.

C
#include <stdio.h>

void print_line(char ch, int count)
{
    for (int i = 0; i < count; i++) {
        putchar(ch);
    }
    putchar('\n');
}

void print_header(void)
{
    print_line('=', 24);
    printf("  Rohtak Sports Club\n");
    print_line('=', 24);
}

int main(void)
{
    print_header();
    printf("Members: 148\n");
    print_line('-', 24);
    return 0;
}
Output
========================
  Rohtak Sports Club
========================
Members: 148
------------------------

print_header calls print_line twice. Functions calling other functions is how large programs are built from small, simple pieces.

Prototypes: declaring before defining

The compiler reads your file from top to bottom. In the examples so far, every function was defined above main, so the compiler already knew it when main called it. Often you want main at the top, where readers look first. Then you add a prototype: a declaration that gives the function's return type, name and parameter types, ending with a semicolon.

C
#include <stdio.h>

double price_with_gst(double price, double rate);   // prototype

int main(void)
{
    double headphones = price_with_gst(1299.0, 18.0);
    printf("Headphones: Rs %.2f\n", headphones);
    printf("Two pairs:  Rs %.2f\n", 2 * headphones);
    return 0;
}

double price_with_gst(double price, double rate)    // definition
{
    return price + price * rate / 100;
}
Output
Headphones: Rs 1532.82
Two pairs:  Rs 3065.64

The prototype lets the compiler check every call: the number of arguments, their types and how the result is used. In larger programs, prototypes go into header files so that many .c files can share them, as you will see in Header Files & Multi-file Programs.

Calling a function that has not been declared is an error in modern C. Since GCC 14, it stops with error: implicit declaration of function. If you see that message, you forgot a prototype or an #include.

Pass by value

C passes arguments by value: the function receives a copy. Changing a parameter inside the function does not change the caller's variable.

C
#include <stdio.h>

void add_bonus(int marks)
{
    marks = marks + 5;
    printf("Inside the function: %d\n", marks);
}

int main(void)
{
    int marks = 70;
    add_bonus(marks);
    printf("Back in main:        %d\n", marks);
    return 0;
}
Output
Inside the function: 75
Back in main:        70

The two variables called marks are separate: one belongs to main, the other to add_bonus. To get a result out of a function, return it: marks = with_bonus(marks);. When a function truly must change the caller's variable, you pass its address, which you will learn in Pointers, NULL & nullptr.

Returning early

A function can have several return statements. As soon as one runs, the function ends. This makes "check and leave" logic short and clear:

C
#include <stdio.h>

bool is_prime(int n)
{
    if (n < 2) {
        return false;
    }
    for (int d = 2; d * d <= n; d++) {
        if (n % d == 0) {
            return false;   // found a divisor: not prime
        }
    }
    return true;
}

int main(void)
{
    printf("Primes up to 30:");
    for (int n = 1; n <= 30; n++) {
        if (is_prime(n)) {
            printf(" %d", n);
        }
    }
    printf("\n");
    return 0;
}
Output
Primes up to 30: 2 3 5 7 11 13 17 19 23 29

The loop only needs to test divisors up to the square root of n (d * d <= n), because any larger divisor would pair with a smaller one already tested. Notice how is_prime reads like a sentence when you call it.

Using the maths library

The header math.h declares functions such as sqrt (square root), pow (power), fabs (absolute value of a double), round and floor. Here is a loan EMI calculator using the standard formula:

C
#include <math.h>
#include <stdio.h>

double emi(double principal, double annual_rate, int months)
{
    double r = annual_rate / 12 / 100;   // monthly rate as a fraction
    double factor = pow(1 + r, months);
    return principal * r * factor / (factor - 1);
}

int main(void)
{
    double monthly = emi(500000.0, 9.0, 60);
    printf("EMI: Rs %.2f\n", monthly);
    printf("Total paid: Rs %.2f\n", monthly * 60);
    return 0;
}
Terminal
gcc -std=c23 -Wall -Wextra emi.c -o emi -lm
./emi
Output
EMI: Rs 10379.18
Total paid: Rs 622750.66

On Linux, the maths functions live in a separate library, so you add -lm at the end of the command to link it. Without it, you may get undefined reference to 'pow'. On macOS and Windows (MSYS2) the option is harmless, so it is a good habit everywhere.

Common mistakes

  • Calling a function before declaring it. Add a prototype above main or move the definition up.
  • Forgetting return in a non-void function. The caller receives garbage. -Wall warns "control reaches end of non-void function".
  • Expecting a parameter change to reach the caller. Parameters are copies. Return the new value instead.
  • Missing -lm on Linux. Linker errors about sqrt or pow mean the maths library was not linked.
  • A prototype that does not match the definition. If the types differ, the compiler reports conflicting types; keep them identical.

Key points

  • A function has a return type, a name, parameters and a body; return sends a value back.
  • void as a return type means "returns nothing"; (void) as the parameter list means "takes nothing".
  • A prototype declares a function before its definition so the compiler can check every call.
  • Arguments are passed by value: the function works on copies.
  • Several return statements let a function finish as soon as it knows the answer.
  • Include math.h for maths functions and link with -lm on Linux.

Exercise

Write a function double to_fahrenheit(double celsius) that converts a temperature using F = C × 9 / 5 + 32. Put its prototype above main and its definition below. In main, use a loop to print a table for 0, 10, 20, 30 and 40 degrees Celsius, with one decimal place for Fahrenheit.

Show solution
C
#include <stdio.h>

double to_fahrenheit(double celsius);

int main(void)
{
    for (int c = 0; c <= 40; c += 10) {
        printf("%3d C = %5.1f F\n", c, to_fahrenheit(c));
    }
    return 0;
}

double to_fahrenheit(double celsius)
{
    return celsius * 9 / 5 + 32;
}
Output
 0 C =  32.0 F
10 C =  50.0 F
20 C =  68.0 F
30 C =  86.0 F
40 C = 104.0 F

Because of the prototype, the compiler knows that to_fahrenheit takes a double, so the int value c is converted automatically. celsius is a double, so celsius * 9 / 5 keeps its fraction.

Quick Quiz

1. What does void mean as a function's return type?

2. Why do you write a prototype above main?

3. After void f(int x) { x = 10; } and int a = 3; f(a);, what is a?

4. Which option links the maths library on Linux?

Learn C with a mentor

Free lessons get you started. Our Java, C & C++ Programming training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call