Function Declaration and Definition
● Declaration (Prototype): Specifies the function's name, parameters, and
return type. Typically placed before the main function or in a header file.
● Definition: Contains the function's implementation (code body). It can be
placed in the same file or a separate implementation file (.cpp).
Benefits:
1. Modularity: Functions divide the program into manageable parts.
2. Reusability: Functions can be reused multiple times without rewriting code.
Example of Separate Declaration and Definition:
#include <iostream>
using namespace std;
// Declaration
int subtract(int a, int b);
int main() {
int result = subtract(15, 5); // Function call
cout << "Result: " << result << endl; // Output: 10
return 0;
}
// Definition
int subtract(int a, int b) {
return a - b;
}
Passing Arguments to Functions
Pass by Value (Copy)
● How it Works: A copy of the argument is passed to the function. The original
variable remains unchanged.
● When to Use: When you want to protect the original data from being modified.
Extended Example:
#include <iostream>
using namespace std;
void display(int x) {
x = 50; // Changes only the local copy
cout << "Inside function, x: " << x << endl;
}
int main() {
int num = 10;
display(num);
cout << "Outside function, num: " << num << endl; // Output: 10
return 0;
}
Pass by Reference
● How it Works: The function receives a reference to the actual argument. Any
modification affects the original variable.
● When to Use: To save memory or when you want the function to modify the
original data.
Extended Example:
#include <iostream>
using namespace std;
void modify(int &x) {
x += 10; // Changes the original variable
}
int main() {
int num = 10;
modify(num);
cout << "After modification, num: " << num << endl; // Output: 20
return 0;
}
Returning Values from Functions
Benefits of Returning Values:
1. Modularity: Encapsulates a computation or logic in a single function.
2. Reusability: The function can be used with different inputs.
Example of Multiple Returns:
#include <iostream>
using namespace std;
int calculate(int a, int b, char operation) {
if (operation == '+') return a + b;
if (operation == '-') return a - b;
if (operation == '*') return a * b;
if (operation == '/') return b != 0 ? a / b : 0; // Avoid division
by zero
return 0;
}
int main() {
cout << "Sum: " << calculate(10, 5, '+') << endl; // Output: 15
cout << "Product: " << calculate(10, 5, '*') << endl; // Output:
50
return 0;
}
Pass by Copy vs. Pass by Reference
Pass by Copy:
● Advantages:
○ Protects the original data.
○ No risk of unintended changes.
● Drawbacks:
○ Less efficient for large data structures like arrays or objects.
Pass by Reference:
● Advantages:
○ Efficient for large data since no copying is involved.
○ Allows modifying the original data.
● Drawbacks:
○ Can lead to bugs if unintended modifications occur.
Mixed Example:
#include <iostream>
using namespace std;
void modify(int copyVar, int &refVar) {
copyVar = 20; // Modifies only the local copy
refVar = 30; // Modifies the original variable
}
int main() {
int a = 10, b = 10;
modify(a, b);
cout << "a (copyVar): " << a << endl; // Output: 10
cout << "b (refVar): " << b << endl; // Output: 30
return 0;
}
Default Arguments: Functions can have default values for parameters.
int add(int a, int b = 5) {
return a + b;
}
cout << add(10); // Output: 15 (b = 5 by default)
cout << add(10, 20); // Output: 30 (b = 20)
Function Overloading: Functions can have the same name but different parameter
lists.
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
Passing Constant References: Protects referenced data from being modified.
void display(const int &x) {
cout << x << endl;
}
1. Scope Rules
Scope defines the region in a program where a variable or function can be
accessed.
● Local Scope: Variables declared inside a function or block are only accessible
within that function or block.
● Global Scope: Variables declared outside all functions are accessible
throughout the program.
● Static Variables: Retain their value between function calls.
Example:
#include <iostream>
using namespace std;
int globalVar = 10; // Global variable
void display() {
int localVar = 20; // Local variable
static int staticVar = 0; // Static variable
staticVar++;
cout << "Global: " << globalVar << ", Local: " << localVar << ",
Static: " << staticVar << endl;
int main() {
display(); // Static: 1
display(); // Static: 2
return 0;
2. Function Call Stack and Activation Record
● Call Stack: Keeps track of active functions during execution.
● Activation Record (Stack Frame): Stores information about a function call,
such as:
○ Local variables
○ Function parameters
○ Return address
Example to Observe Stack Behavior:
#include <iostream>
using namespace std;
void funcB() {
cout << "Inside funcB" << endl;
void funcA() {
cout << "Inside funcA" << endl;
funcB();
}
int main() {
cout << "Inside main" << endl;
funcA();
return 0;
Call Stack Behavior:
1. main calls funcA.
2. funcA is pushed onto the stack.
3. funcA calls funcB, which is pushed onto the stack.
4. funcB completes and is popped off the stack.
5. funcA completes and is popped off the stack.
6. main completes.
3. Functions with Empty Parameter Lists
Functions can be defined without parameters. Useful when no external input is
needed.
Example:
#include <iostream>
using namespace std;
void greet() {
cout << "Hello, World!" << endl;
}
int main() {
greet();
return 0;
4. Inline Functions
● An inline function replaces its call with its body to reduce function call
overhead.
● Typically used for small, frequently called functions.
● Use the inline keyword.
Example:
#include <iostream>
using namespace std;
inline int square(int x) {
return x * x;
int main() {
cout << "Square of 5: " << square(5) << endl; // Inline
replacement
return 0;
Notes:
1. The compiler may ignore the inline suggestion for complex functions.
2. Inline functions can increase the binary size if overused.
5. References and Reference Parameters
● A reference is an alias for an existing variable.
● Reference Parameters allow passing variables by reference.
Example:
#include <iostream>
using namespace std;
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
int main() {
int x = 10, y = 20;
swap(x, y);
cout << "x: " << x << ", y: " << y << endl; // Output: x: 20, y:
10
return 0;
6. Default Arguments
Default values can be assigned to function parameters.
Example:
#include <iostream>
using namespace std;
void greet(string name = "User") {
cout << "Hello, " << name << "!" << endl;
int main() {
greet(); // Default argument: User
greet("Alice"); // Custom argument: Alice
return 0;
Notes:
1. Default arguments must be defined from right to left in the parameter list.
2. Example: void func(int a, int b = 10, int c = 20);
7. Unary Scope Resolution Operator
The scope resolution operator (::) is used to:
1. Access global variables when local variables shadow them.
2. Define functions outside the class in object-oriented programming.
3. Specify namespaces.
Example:
#include <iostream>
using namespace std;
int value = 100; // Global variable
int main() {
int value = 50; // Local variable
cout << "Local value: " << value << endl; // Output: 50
cout << "Global value: " << ::value << endl; // Output: 100
return 0;
8. Recursion vs. Iteration
● Recursion: A function calls itself to solve a problem.
○ Advantages: Elegant for problems like factorial, Fibonacci, etc.
○ Disadvantages: Uses more memory (stack).
● Iteration: Uses loops to repeat code.
○ Advantages: More efficient in terms of memory.
○ Disadvantages: Less intuitive for some problems.
Recursion Example:
#include <iostream>
using namespace std;
int factorial(int n) {
if (n == 0 || n == 1) return 1; // Base case
return n * factorial(n - 1); // Recursive case
int main() {
cout << "Factorial of 5: " << factorial(5) << endl; // Output: 120
return 0;
Iteration Example:
#include <iostream>
using namespace std;
int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; ++i) {
result *= i;
return result;
int main() {
cout << "Factorial of 5: " << factorial(5) << endl; // Output: 120
return 0;