Functions
What are Functions?
Functions are reusable blocks of code that perform specific tasks. They help organize code, reduce repetition, and make programs more modular and maintainable.
Function Anatomy
return_type function_name
(parameters) {
// function body
return value;
} Basic Function Declaration
Here's how to declare and use basic functions:
Simple Functions
#include <iostream>
using namespace std;
// Function declaration (prototype)
void greet();
int add(int a, int b);
double calculateArea(double radius);
int main() {
greet();
int sum = add(5, 3);
cout << "Sum: " << sum << endl;
double area = calculateArea(2.5);
cout << "Area: " << area << endl;
return 0;
}
// Function definitions
void greet() {
cout << "Hello, World!" << endl;
}
int add(int a, int b) {
return a + b;
}
double calculateArea(double radius) {
const double PI = 3.14159;
return PI * radius * radius;
}Function Parameters
Functions can accept parameters in different ways:
Parameter Passing
#include <iostream>
using namespace std;
// Pass by value
void passByValue(int x) {
x = 100; // Only changes local copy
cout << "Inside function: " << x << endl;
}
// Pass by reference
void passByReference(int& x) {
x = 100; // Changes original variable
cout << "Inside function: " << x << endl;
}
// Pass by pointer
void passByPointer(int* x) {
*x = 100; // Changes original variable
cout << "Inside function: " << *x << endl;
}
// Const parameters
void printValue(const int& value) {
cout << "Value: " << value << endl;
// value = 50; // Error: cannot modify const parameter
}
int main() {
int num = 10;
cout << "Original value: " << num << endl;
passByValue(num);
cout << "After pass by value: " << num << endl;
passByReference(num);
cout << "After pass by reference: " << num << endl;
num = 20;
passByPointer(&num);
cout << "After pass by pointer: " << num << endl;
printValue(num);
return 0;
}Function Overloading
C++ allows multiple functions with the same name but different parameters:
Function Overloading Example
#include <iostream>
using namespace std;
// Overloaded functions
int multiply(int a, int b) {
return a * b;
}
double multiply(double a, double b) {
return a * b;
}
int multiply(int a, int b, int c) {
return a * b * c;
}
// Display functions for different types
void display(int value) {
cout << "Integer: " << value << endl;
}
void display(double value) {
cout << "Double: " << value << endl;
}
void display(const string& value) {
cout << "String: " << value << endl;
}
int main() {
// Compiler chooses the right function based on arguments
cout << multiply(3, 4) << endl; // Calls int version
cout << multiply(3.5, 2.5) << endl; // Calls double version
cout << multiply(2, 3, 4) << endl; // Calls three-parameter version
display(42);
display(3.14159);
display("Hello World");
return 0;
}Default Parameters
Functions can have default parameter values:
Default Parameters Example
#include <iostream>
using namespace std;
// Function with default parameters
void printInfo(const string& name, int age = 18, const string& city = "Unknown") {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "City: " << city << endl;
cout << "---" << endl;
}
// Calculate power with default exponent
double power(double base, int exponent = 2) {
double result = 1;
for (int i = 0; i < exponent; i++) {
result *= base;
}
return result;
}
int main() {
// Different ways to call functions with default parameters
printInfo("Alice"); // Uses default age and city
printInfo("Bob", 25); // Uses default city
printInfo("Charlie", 30, "New York"); // No defaults used
cout << "2^2 = " << power(2) << endl; // Uses default exponent (2)
cout << "2^3 = " << power(2, 3) << endl; // Specifies exponent
cout << "5^4 = " << power(5, 4) << endl; // Specifies exponent
return 0;
}Recursive Functions
Functions can call themselves to solve problems recursively:
Recursion Examples
#include <iostream>
using namespace std;
// Calculate factorial recursively
long long factorial(int n) {
if (n <= 1) {
return 1; // Base case
}
return n * factorial(n - 1); // Recursive case
}
// Calculate Fibonacci number recursively
long long fibonacci(int n) {
if (n <= 1) {
return n; // Base cases: fib(0) = 0, fib(1) = 1
}
return fibonacci(n - 1) + fibonacci(n - 2); // Recursive case
}
// Calculate sum of digits recursively
int sumOfDigits(int n) {
if (n == 0) {
return 0; // Base case
}
return (n % 10) + sumOfDigits(n / 10); // Recursive case
}
int main() {
cout << "Factorial of 5: " << factorial(5) << endl;
cout << "Factorial of 10: " << factorial(10) << endl;
cout << "\nFibonacci sequence:" << endl;
for (int i = 0; i < 10; i++) {
cout << fibonacci(i) << " ";
}
cout << endl;
cout << "\nSum of digits in 12345: " << sumOfDigits(12345) << endl;
cout << "Sum of digits in 987: " << sumOfDigits(987) << endl;
return 0;
}Lambda Functions (C++11)
Lambda functions provide a concise way to define anonymous functions:
Lambda Functions
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
// Basic lambda function
auto greet = []() {
cout << "Hello from lambda!" << endl;
};
greet();
// Lambda with parameters
auto add = [](int a, int b) {
return a + b;
};
cout << "Sum: " << add(5, 3) << endl;
// Lambda with capture
int multiplier = 10;
auto multiply = [multiplier](int x) {
return x * multiplier;
};
cout << "5 * 10 = " << multiply(5) << endl;
// Using lambda with STL algorithms
vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Count even numbers
int evenCount = count_if(numbers.begin(), numbers.end(),
[](int n) { return n % 2 == 0; });
cout << "Even numbers count: " << evenCount << endl;
// Transform all numbers (multiply by 2)
transform(numbers.begin(), numbers.end(), numbers.begin(),
[](int n) { return n * 2; });
cout << "Doubled numbers: ";
for (int n : numbers) {
cout << n << " ";
}
cout << endl;
return 0;
}Function Best Practices
Single Responsibility
Each function should do one thing and do it well
Meaningful Names
Use descriptive names that clearly indicate what the function does
Keep Functions Small
Aim for functions that fit on one screen (20-30 lines max)
Use const Correctly
Mark parameters const when they shouldn't be modified
Avoid Global Variables
Pass data through parameters instead of using global variables
Handle Edge Cases
Consider and handle invalid inputs and edge cases