Tail Call Optimisation in C
Last Updated :
06 Sep, 2023
In C programming, Tail Call Optimization (TCO) is a technique that eliminates the need for an additional stack frame to store the data of another function by reusing the current function's stack frame. This optimization technique is only possible for tail function calls.
What is Tail Call?
The tail call is the type of function call where another function is called as the last action of the current function. Here, the function call is present as the last statement at the end of the current function's body.
The tail call optimization is most useful in tail recursion where the last thing a function does is to call itself. In such cases, it converts the recursive function to an iterative function by reusing the current stack frame for all function calls. It helps in reducing the space complexity of the recursive function.
Example
Let's consider a hypothetical scenario, We need to call a recursive function that calculates the factorial of a number modulo a prime number say 'prime'.
C
// C Program to illustrate Tail Call Optimization
#include <stdio.h>
// Program to find factorial of a number n modulo prime
int factorial(int n, int prime)
{
if (n <= 1) {
// base case
return 1;
}
return (n * factorial(n - 1, prime) % prime) % prime;
}
int main()
{
// Calling for the factorial of 5
int result = factorial(5, 1000000007);
printf("%d\n", result);
return 0;
}
This program will take up a lot of time and a significant amount of memory. Let us look at the function call stack for n = 6.
main()
\
factorial(5)
\
factorial(4)
\
factorial(3)
\
factorial(2)
\
factorial(1)
Space Complexity: O(n)
So, without an optimization technique, a function like this would stack overflow for large values of n.
Optimizing the Above Function
This is where TCO comes into the picture, using which the compiler can avoid the creation of a new stack frame, under the condition that the call made is the last operation in the function in which it is called.
TCO technique uses the current function's stack frame for the new function call. This helps prevent stack overflow errors for deep recursive calls and thus increases the efficiency of the program.
C
// C program to illustrate Tail Call Optimisation
#include <stdio.h>
// this function calculates factorial modulo prime
int factorial(int store, int num, int prime) {
if (num < 1) {
// Base case
return store;
}
return factorial((store%prime * num%prime)%prime, num - 1, prime);
}
int main(){
int result = factorial(1,5,1000000007);
printf("%d\n", result);
return 0;
}
Explanation
The existing frame can be directly over-written by the compiler: the old value of num is multiplied by the old value of store and the result is written back into the store variable. The compiler can now decrement num by overwriting the previous value and jump to the beginning of the factorial function. Note that here, we are making sure that instead of the multiplication operation, the function call is the last operation in the above code that needs to be executed.
Note: Not all recursive functions can be optimized using such techniques. The reason is that complex recursive functions where the recursive call is not the last operation and additional operations after the call are present are not suitable for Tail Call Optimization.
Tail Call Optimization in C
Impact on Space Complexity
Since there is no need to preserve stack frames of the previous function call, the new function call's stack frame overrides the stack frame of the previous call, constant space is required, i.e. O(1) instead of O(n).
Advantages of Tail Call Optimization
- Significant reduction in stack space usage, reducing the risk of running into stack overflow.
- Improvement in performance due to reduction in overhead of managing stack frames, leading to faster execution.
- Supports functional programming, where recursion is commonly used for solving problems.
Related Articles:
Similar Reads
C Programming Language Tutorial C is a general-purpose mid-level programming language developed by Dennis M. Ritchie at Bell Laboratories in 1972. It was initially used for the development of UNIX operating system, but it later became popular for a wide range of applications. Today, C remains one of the top three most widely used
5 min read
Dynamic Memory Allocation in C using malloc(), calloc(), free() and realloc() In C, a variable defined in a function is stored in the stack memory. The requirement of this memory is that it needs to know the size of the data to memory at compile time (before the program runs). Also, once defined, we can neither change the size nor completely delete the memory.To resolve this,
9 min read
Data Types in C Each variable in C has an associated data type. It specifies the type of data that the variable can store like integer, character, floating, double, etc.Example:C++int number;The above statement declares a variable with name number that can store integer values.C is a statically type language where
5 min read
C Language Introduction C is a general-purpose procedural programming language initially developed by Dennis Ritchie in 1972 at Bell Laboratories of AT&T Labs. It was mainly created as a system programming language to write the UNIX operating system.Main features of CWhy Learn C?C is considered mother of all programmin
6 min read
C Arrays An array in C is a fixed-size collection of similar data items stored in contiguous memory locations. It can be used to store the collection of primitive data types such as int, char, float, etc., as well as derived and user-defined data types such as pointers, structures, etc. Creating an Array in
7 min read
C Pointers A pointer is a variable that stores the memory address of another variable. Instead of holding a direct value, it has the address where the value is stored in memory. This allows us to manipulate the data stored at a specific memory location without actually using its variable. It is the backbone of
9 min read
Phases of a Compiler A compiler is a software tool that converts high-level programming code into machine code that a computer can understand and execute. It acts as a bridge between human-readable code and machine-level instructions, enabling efficient program execution. The process of compilation is divided into six p
10 min read
C Programs To learn anything effectively, practicing and solving problems is essential. To help you master C programming, we have compiled over 100 C programming examples across various categories, including basic C programs, Fibonacci series, strings, arrays, base conversions, pattern printing, pointers, and
8 min read
Two Sum - Pair with given Sum Given an array arr[] of n integers and a target value, the task is to find whether there is a pair of elements in the array whose sum is equal to target. This problem is a variation of 2Sum problem.Examples: Input: arr[] = [0, -1, 2, -3, 1], target = -2Output: trueExplanation: There is a pair (1, -3
15+ min read
Basics of File Handling in C File handling in C is the process in which we create, open, read, write, and close operations on a file. C language provides different functions such as fopen(), fwrite(), fread(), fseek(), fprintf(), etc. to perform input, output, and many different C file operations in our program.Need of File Han
13 min read