C++ Function Fundamentals for Competitive Programming
Essential C++ Function Concepts
When preparing for coding competitions like LeetCode, understanding C++ function mechanics is crucial. This guide covers four fundamental function concepts that frequently appear in competitive programming scenarios.
1. Inline Functions
An inline function is declared by placing the inline keyword before the function definition. Unlike regular functions that involve call overhead (storing return addresses, managing stack frames), inline functions suggest the compiler insert the function's code directly at the call site.
How Inline Functions Work
During compilation, the source code transforms into machine language instructions stored at specific memory addresses. When executing a regular function call, the program jumps to the function's memory location, executes the code, and returns to the original position. This involves stack operations for parameters and return address preservation.
Inline functions eliminate this overhead by replacing the function call with the actual function body, trading increased code size for faster execution.
Implementation Example
inline int add(int x, int y)
{
return x + y;
}
Inline Functions vs Macros
C programmers often use preprocessor macros like #define SQUARE(X) X*X. However, macros perform blind text substitution, leading to unexpected behavior:
#define SQUARE(X) ((X)*(X))
// With macro expansion:
result = SQUARE(5.0); // result = 5.0 * 5.0 ✓
result = SQUARE(4.5+7.5); // result = 4.5+7.5 * 4.5+7.5 ✗
result = SQUARE(c++); // result = c++ * c++ (c incremented twice!) ✗
Inline funcsions evaluate arguments once, avoiding multiple evaluation side effects. Use inline functions for small operations where functon call overhead exceeds the actual computation time.
2. Default Parameters
Default parameters allow functions to provide fallback values when arguments are omitted during invocation.
Basic Syntax
int calculate(int a = 10, int b = 20, int c = 30)
{
return a + b + c;
}
When calling calculate() without arguments, it returns 60. Calling calculate(5) returns 55.
Complex Example
void display(char symbol = 'b', int count = 2, const char* msg = "XY")
{
std::cout << symbol << "," << count << "," << msg << std::endl;
}
3. Default Arguments Rules
Default arguments are matched from left to right. The key constraint: default arguments must be contiguous from the right side. Any parameter with a default value cannot be followed by a parameter without one.
Valid Implementation
void process(char code, int value, const char* label = "DEFAULT")
{
std::cout << code << "," << value << "," << label << std::endl;
}
Invalid Implementation
// INCORRECT - gaps in default arguments
void process(char code = 'X', int value, const char* label)
{
// Compilation error: default argument not allowed for 'value'
}
Reason: If we call process('A', 100), the compiler cannot determine whether 100 should be assigned to value or label. Default arguments must trail without gaps.
4. Placeholder Parameters
Placeholder parameters (sometimes called dummy parameters) allow unnamed parameters in function declarations.
Syntax
void compute(int, int storage, int)
{
std::cout << storage << std::endl;
}
int main()
{
compute(1, 2, 3);
// All three arguments required, but only 'storage' is named
}
All arguments must still be passed during the function call, but only named parameters are accessible within the function body.
Use Case: API Versioning
Placeholder parameters excel when maintaining backward compatibility:
// Original API version 1
int combine(int first, int second, int third)
{
return first + second + third;
}
// Updated API version 2 - only returns the middle value
int combine(int, int middle, int)
{
return middle;
}
Existing client code calling combine(a, b, c) continues working without modification. The function signature remains compatible while internal behavior changes, eliminating the need to update all call sites throughout the codebase.