Skip to content

C Functions

A function is a self-contained block of code that performs a specific task. Functions are essential for structuring programs, promoting code reuse, and improving readability and maintainability. Every C program must have at least one function: main(), which is the entry point of execution.

Breaking down complex problems into smaller, manageable tasks, each handled by a function, is a fundamental principle of procedural programming.

  • Function Definition: Provides the actual implementation (the code) of the function.
  • Function Declaration (Prototype): Tells the compiler about the function’s name, return type, and the types of its parameters. This allows the compiler to check calls to the function even before it encounters the function’s definition.
  • Function Call: Executes the code within the function definition.

The C standard library provides a rich set of pre-defined functions (like printf(), scanf(), strcpy(), malloc(), etc.) that you can call in your programs after including the appropriate header files.

The general syntax for defining a function in C is:

return_type function_name(parameter_type1 parameter_name1, parameter_type2 parameter_name2, ...) {
// Function body: declarations and statements
// ... code to perform the task ...
return value; // Optional: only if return_type is not void
}

Components of a function definition:

  • Return Type: The data type of the value the function sends back to the caller. If the function doesn’t return a value, use the keyword void.
  • Function Name: A unique identifier for the function. Follow standard C naming conventions (e.g., letters, numbers, underscores; cannot start with a number).
  • Parameters (Arguments): Variables listed inside the parentheses that receive values (arguments) when the function is called. They act as local variables within the function. If a function takes no parameters, use (void): return_type function_name(void) { ... }.
  • Function Body: The code block enclosed in curly braces {} containing the instructions the function executes.

Example: A function to find the maximum of two integers

Section titled “Example: A function to find the maximum of two integers”
/*
* Function definition for max
* Takes two integers as input
* Returns the larger of the two integers
*/
int max(int num1, int num2) { // Function header
// Function body starts here
int result; // Local variable declaration
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result; // Return the calculated maximum value
}

A function declaration, also known as a prototype, informs the compiler about the function’s signature before it’s called or defined. This is crucial if you call a function before its definition appears in the source code, or if the function is defined in a different source file.

The syntax is similar to the function header, but ends with a semicolon and parameter names are optional (though often useful for clarity):

return_type function_name(parameter_type1, parameter_type2, ...);

For the max function defined above, the prototype would be:

int max(int num1, int num2); // Prototype with parameter names
// or equivalently:
int max(int, int); // Prototype without parameter names

Prototypes are typically placed at the top of the source file or in header files (.h) which are then included using #include.

To use a function, you call it by using its name followed by parentheses containing the arguments (the actual values or variables being passed to the function’s parameters).

  1. Control transfers from the calling point to the first statement in the function’s body.
  2. The values of the arguments are copied into the corresponding function parameters.
  3. The function body executes.
  4. If a return statement with a value is encountered, that value is sent back to the caller, and control returns to the point immediately after the function call.
  5. If the function’s return type is void or the end of the function body (}) is reached without a return statement, control simply returns to the caller.

Example: Calling the max function

#include <stdio.h>
#include <stdlib.h> // For EXIT_SUCCESS
// Function prototype (declaration) - Essential here because max is defined after main
int max(int num1, int num2);
int main(void) { // Standard main signature
int a = 100;
int b = 200;
int ret;
// Calling the function and storing the returned value
ret = max(a, b);
printf("Max value is: %d\n", ret);
return EXIT_SUCCESS;
}
// Function definition
int max(int num1, int num2) {
int result;
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result;
}

Compiling and running this code produces:

Max value is: 200

Parameters declared in the function definition are called formal parameters. The values passed during a function call are called actual arguments.

C uses pass by value by default for function arguments. This means:

  • Call by Value: A copy of the actual argument’s value is made and passed to the formal parameter. Changes made to the parameter inside the function do not affect the original argument in the caller.
  • Simulating Call by Reference (Pass by Pointer): To allow a function to modify the original variable in the caller, you must pass the address of the variable (using the & operator) as the argument. The corresponding formal parameter must be declared as a pointer (e.g., int *ptr). Inside the function, you use the dereference operator (*) to access or modify the value at that address. This simulates call by reference.

The max function example uses call by value. The values of a and b are copied into num1 and num2. If max tried to modify num1 or num2, it would not change a or b in main.

Example of Pass by Pointer (Simulating Call by Reference):

#include <stdio.h>
#include <stdlib.h>
// Function prototype: takes a pointer to an integer
void increment(int *value_ptr);
int main(void) {
int counter = 10;
printf("Before increment: %d\n", counter);
// Pass the address of 'counter' to the function
increment(&counter);
printf("After increment: %d\n", counter); // Original 'counter' is modified
return EXIT_SUCCESS;
}
// Function definition: parameter is a pointer
void increment(int *value_ptr) {
// Dereference the pointer to access and modify the original value
(*value_ptr)++;
// Parentheses are important due to operator precedence
// Alternatively: *value_ptr = *value_ptr + 1;
}

Output:

Before increment: 10
After increment: 11