C Functions
A function in C is a named block of code that performs a specific task. Functions matter because they let you split a program into small, understandable pieces instead of putting every statement inside main.
You have already used library functions such as printf. In this lesson, you will define your own functions, call them, return values, and understand what C does when control jumps into and out of a function.
Overview: How C Functions Work
Every C program starts by calling the function named main. From there, your program may call other functions. A function call temporarily transfers execution to the function body. When the function finishes, execution returns to the statement after the call.
A function has a return type, a name, a parameter list in parentheses, and a body in braces. The return type tells the compiler what kind of value the function sends back. A function declared with void as its return type performs an action but does not return a useful value.
Functions also create boundaries in your program. Variables declared inside a function are local to that function. They exist while the function call is active and are normally gone when the function returns. This is one reason functions are useful: each function can have its own temporary variables without interfering with variables in another function.
At compile time, C checks that a function is known before it is called. The compiler needs to know the function’s return type and parameter types so it can check the call correctly. You can satisfy this by defining the function before main, or by writing a function declaration, also called a prototype, before main and placing the full definition later.
Good functions are usually small and focused. A function named printHeader should print a header; a function named getScore should return a score. Clear function names make a program read like a sequence of meaningful steps.
Syntax
This complete program shows the general shape of a function definition and a prototype:
#include <stdio.h>
int functionName(void);
int main(void)
{
printf("Value: %d\n", functionName());
return 0;
}
int functionName(void)
{
return 10;
}
Output:
Value: 10
| Part | Meaning |
|---|---|
return_type |
The type of value the function returns, such as int, double, char, or void. |
function_name |
The identifier used to call the function. It follows normal C naming rules. |
parameter_list |
The values the function can receive. Use void when the function takes no parameters. |
statements |
The work performed when the function is called. |
return |
Sends a value back to the caller and ends the current function call. |
A prototype has the same return type, name, and parameter types, but it ends with a semicolon and has no body, such as int getScore(void);.
Examples
Calling a simple function
#include <stdio.h>
void printLine(void)
{
printf("--------------------\n");
}
int main(void)
{
printLine();
printf("Daily Report\n");
printLine();
return 0;
}
Output:
--------------------
Daily Report
--------------------
The function printLine takes no parameters and returns no value. The two calls inside main run the same function body twice. This removes duplicated printf statements and gives the repeated action a useful name.
Returning a value
#include <stdio.h>
int getPassingScore(void)
{
return 70;
}
int main(void)
{
int score = getPassingScore();
printf("Passing score: %d\n", score);
printf("With bonus: %d\n", getPassingScore() + 5);
return 0;
}
Output:
Passing score: 70
With bonus: 75
The function getPassingScore returns an int. The returned value can be stored in a variable, printed, compared, or used inside a larger expression. When return 70; runs, the function ends immediately and gives 70 back to the call site.
Using a prototype
#include <stdio.h>
int getCurrentYear(void);
void printWelcome(void);
int main(void)
{
printWelcome();
printf("Year: %d\n", getCurrentYear());
return 0;
}
void printWelcome(void)
{
printf("Welcome to C functions.\n");
}
int getCurrentYear(void)
{
return 2026;
}
Output:
Welcome to C functions.
Year: 2026
Here, main appears before the full function definitions. The prototypes tell the compiler that printWelcome and getCurrentYear exist, what they return, and that they take no parameters. Without those declarations, a modern C compiler should diagnose the calls before the definitions.
Combining functions in a realistic flow
#include <stdio.h>
int readBaseScore(void);
int getBonus(void);
void printFinalScore(int finalScore);
int main(void)
{
int baseScore = readBaseScore();
int bonus = getBonus();
int finalScore = baseScore + bonus;
printFinalScore(finalScore);
return 0;
}
int readBaseScore(void)
{
return 82;
}
int getBonus(void)
{
return 8;
}
void printFinalScore(int finalScore)
{
printf("Final score: %d\n", finalScore);
}
Output:
Final score: 90
This program is still small, but it shows a useful habit: main describes the high-level flow while helper functions handle separate tasks. The parameter in printFinalScore receives the final number to print. Parameters are covered more deeply in the next lesson, but this example shows how functions work together.
How It Works Step By Step
When the program starts, the C runtime calls main. Inside main, each function call evaluates its arguments first, then transfers control to the called function. The called function gets its own execution context, often described as a stack frame. That context stores information such as local variables, parameter values, and where execution should return afterward.
For example, in int score = getPassingScore();, the program enters getPassingScore. The statement return 70; produces an integer result and ends that call. Control returns to main, and the result is assigned to score.
A non-void function must return a value that is compatible with its declared return type. Returning a double from a function declared as int may convert the value and lose information. Reaching the end of a non-void function without returning a value is undefined behavior if the caller tries to use the result.
A void function may use return; with no value to exit early, or it may simply reach the closing brace. It must not return a value because the caller is not expecting one.
Common Mistakes
Calling a function before declaring it
C needs a declaration before a call. This call is a mistake if the compiler has not already seen a definition or prototype for getAnswer. The corrected version places a prototype before main:
#include <stdio.h>
int getAnswer(void);
int main(void)
{
printf("Answer: %d\n", getAnswer());
return 0;
}
int getAnswer(void)
{
return 42;
}
Output:
Answer: 42
The prototype int getAnswer(void); is a promise about the function’s interface. The later definition must match that promise.
Forgetting to return a value
If a function promises to return an int, every normal path should return an int. Do not write a non-void function that performs work but falls off the end. A corrected version returns the computed result explicitly:
#include <stdio.h>
int square(void)
{
int value = 6;
return value * value;
}
int main(void)
{
printf("Square: %d\n", square());
return 0;
}
Output:
Square: 36
The return statement makes the function’s contract complete: callers can rely on receiving an integer result.
Confusing a function call with a function name
The parentheses are part of the call. Writing only the function name refers to the function itself, not the act of running it. Use parentheses when you want the body to execute:
#include <stdio.h>
void showReady(void)
{
printf("Ready\n");
}
int main(void)
{
showReady();
return 0;
}
Output:
Ready
The statement showReady(); calls the function. The semicolon ends the call statement.
Best Practices
- Give each function one clear job, and name it after that job.
- Use
voidin an empty parameter list, such asint getCount(void), to clearly say that no arguments are accepted. - Write prototypes near the top of the file when function definitions appear after
main. - Keep return types honest. If a function calculates a value, return it; if it only performs an action, use
void. - Prefer readable function names such as
printMenuorcalculateTotalover vague names such asdoStuff. - Avoid very large functions. When a function becomes hard to scan, split part of its work into a helper function.
- Compile with warnings enabled, such as
-Wall -Wextra, so mismatched declarations and missing returns are easier to catch.
Practice Exercises
- Write a function named
printTitlethat prints a two-line title, then call it frommain. - Write a function named
getTaxRatethat returns7, then printTax rate: 7%frommain. - Write prototypes for two functions, define them after
main, and call both frommain. One function should return anint, and the other should returnvoid.
Summary
- A function is a named block of C code that can be called from another part of the program.
- A function definition includes a return type, name, parameter list, and body.
voidmeans a function returns no value, or accepts no parameters when used in the parameter list.- A non-
voidfunction should return a value compatible with its return type. - A prototype lets the compiler check calls before it has seen the full function definition.
- Function calls create temporary execution contexts for local work, then return control to the caller.
