Lecture#1
Lecture#1
Programming
Lecture#1
Irfan Latif
Outline
• Functions, Pass-by-Value, Pass-by-Reference
• Function Overloading
• Default Arguments
• Dynamic Memory Allocation
• Dangling Pointers, and Memory
Functions
• A function is a self-contained block of code designed to perform a
specific task. Functions allow us to divide programs into smaller,
manageable parts, which makes coding more organized and reusable.
• By using functions, we can avoid redundancy and keep our code more
readable and easier to debug.
Why Do We Use Functions?
• Reusability: You can write a function once and use it
multiple times throughout the program.
• Modularity: Breaking down a large program into smaller
functions makes it easier to understand and maintain.
• Abstraction: Functions allow you to hide complex details and
expose only the necessary interface.
• Maintainability: If a function's behavior needs to be changed, it
can be modified in one place, and the changes will
automatically be reflected wherever the function is used.
Functions in Programming
Definition: A function is a reusable block of code that performs a specific task when called.
•It helps in breaking down complex problems into smaller, manageable parts.
Syntax:
return_type function_name(parameter_list) { // body of the function // return statement }
Components:
Return Type: Type of value returned by the function (e.g., int, void).
Function Name: Identifier for the function.
Parameter List: Variables passed to the function (optional).
Types of Functions:
Standard Functions: Built-in functions provided by the language (e.g., printf, scanf in C/C++).
User-defined Functions: Functions defined by the user to perform specific tasks.
Three Steps of a Function in C++
1.Function Declaration (Prototype)
2.Function Definition (Implementation)
3.Function Calling (Invocation)
Three Step Solution Example
#include <iostream>
using namespace std;
int main() {
int result = add(10, 5); // 3. Function Call
cout << "The result is: " << result << endl; // Output: 15
return 0;
}
// 2. Function Definition
int add(int a, int b) {
return a + b;
}
Pass-by-Value
Definition: Pass-by-value is a method of passing arguments to a function where the value of the
argument is copied into the function’s parameter.
Characteristics:
Isolation: Changes made to the parameter do not affect the original argument.
Efficiency: Ideal for small data types (e.g., integers, characters).
Example:
void updateValue(int num) { num = num + 10; // Changes only within the function }
int main() { int value = 5;
updateValue(value); // value is still 5 }
Key Points:
Useful when you want to ensure that the original data remains unchanged.
Can lead to overhead due to copying, especially for large data structures.
Example#1- Pass by Value
#include <iostream>
using namespace std;
int func(int a, int b)
{ a = 3;
b = 4;
int sum a+b;
return sum;}
int main()
{ int x = 10;
int y = 20;
int s;
s= func(x, y);
cout << s << endl;
}
Example#2 - Pass by Value
#include <iostream>
using namespace std;
void modify(int a) {
a = 10;
}
int main() {
int x = 5;
modify(x);
cout << "Value of x: " << x << endl; // Output: 5
}
Output: Output: 5
Pass-by-Reference
Definition: Pass-by-reference is a method of passing arguments to a function where the
reference (address) of the argument is passed, allowing the function to modify the original data.
Characteristics:
Mutability: Changes made to the parameter affect the original argument.
Efficiency: More efficient for large data structures (e.g., arrays, structs) since no copying occurs.
Example:
void updateValue(int &num) { num = num + 10; // Changes affect the original
variable }
int main() { int value = 5;
updateValue(value); // value is now 15 }
Key Points:
Commonly used for large objects to avoid unnecessary copying.
Helps in achieving results in functions without returning a value.
Example 1 - Pass by Reference
#include <iostream>
using namespace std;
void modify(int& a) {
a = 10;
}
int main() {
int x = 5;
modify(x);
cout << "Value of x: " << x << endl; // Output: 10
}
Output: Output: 10
#include <iostream>
using namespace std;
// function definition to swap values
void swap(int& n1, int& n2) {
int temp;
temp = n1;
n1 = n2;
n2 = temp;}
int main() { // initialize variables
int a = 1, b = 2;
cout << "Before swapping" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
// call function to swap numbers
swap(a, b);
cout << "\nAfter swapping" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}
Function Overloading
Definition: Function overloading is a feature that allows multiple functions to have the same
name but with different parameters (number or type).
Characteristics:
Parameter Differentiation: Compiler differentiates functions based on their parameter lists.
Code Reusability: Reduces the need for multiple function names for similar operations.
Example:
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
int main() { int sumInt = add(5, 10); // Calls int version
double sumDouble = add(5.5, 2.3); // Calls double version }
Key Points:
Enhances code readability and maintainability.
Function signatures (parameter types and count) must differ for overloading.
Example 1 - Function Overloading
#include <iostream>
using namespace std;
Definition: Default arguments allow a function to be called with fewer arguments than it is defined
to accept by assigning default values to parameters.
Characteristics:
Optional Parameters: Reduces the need for overloads for similar functions.
Right to Left: Default arguments must be specified from right to left in the parameter list.
Example:
void display(int a, int b = 10) { cout << "a: " << a << ", b: " << b << endl; }
int main() { display(5); // b takes default value 10 display(5, 15); // b takes value 15 }
Key Points:
Enhances flexibility in function calls.
Default values must be specified in the function declaration, not in the definition.
Example 1 - Default Arguments
#include <iostream>
using namespace std;
int main() {
cout << "Add with one argument: " << add(5) << endl; // Output: 15
cout << "Add with two arguments: " << add(5, 3) << endl; // Output: 8
}
Output: Output: Add with one argument: 15
Output: Add with two arguments: 8
Dynamic Memory Allocation
Definition: Dynamic memory allocation is the process of allocating memory at runtime using pointers.
Functions:
new: Allocates memory.
delete: Deallocates memory.
Example:
int* ptr = new int; // Allocates memory for an integer
*ptr = 20; // Assigning value
delete ptr; // Deallocating memory
Key Points:
Essential for managing memory efficiently, especially in large data applications.
Avoids stack overflow for large data structures.
Example 1 - Dynamic Memory
Allocation
#include <iostream>
using namespace std;
int main() {
int* p = new int(10);
cout << "Allocated value: " << *p << endl; // Output: 10
delete p;
return 0;
}
Output: Output: Allocated value: 10
Dangling Pointers
Definition: A dangling pointer is a pointer that does not point to a valid object of the appropriate type.
This usually occurs after the memory it points to has been deallocated.
Causes:
Deleting an object and still using its pointer.
Returning a pointer to a local variable that goes out of scope.
Example:
int main() {
int* p = new int;
*p = 10,
delete p; // Now p is a dangling pointer
cout<<p; // Accessing *p here is undefined behavior
return 0;
}
• Output: Output: (Undefined behavior)
How to avoid dangling pointer
• To avoid creating dangling pointers, you need to carefully manage
dynamic memory and follow some best practices.
1. Set pointers to nullptr after deletion
• delete p;
p = nullptr;
2. Avoid using pointers after delete
Memory Leakage
Definition: Memory leakage occurs when dynamically allocated memory is not properly deallocated,
leading to reduced available memory and potentially causing program crashes.
Consequences:
Reduces available memory for the system.
Can lead to slow performance and instability.
Example:
void leakMemory() { int* leak = new int[100]; // Memory allocated but not deallocated // No
delete statement }
int main() { leakMemory(); // Causes memory leak }
Prevention:
Always deallocate memory using delete or delete[] after use.
Use smart pointers (e.g., std::unique_ptr, std::shared_ptr) in C++ for automatic memory management.
Memory Leakage
• In C++, there is no automatic garbage collection. It means that any
memory that is dynamically allocated by the programmer needs to be
freed after its usage manually by the programmer.
• If the programmer forgets to free this memory, it will occupy the
space from till the program lives and will be unavailable to other
processes. This is called memory leak.
Example 1 - Memory Leak
#include <iostream>
using namespace std;
int main() {
int* p = new int(10);
// Memory leak: no delete for p
return 0;
}
Output: Output: (Memory leakage)
Example 2 - Memory Leak
#include <iostream>
using namespace std;
void func_to_show_mem_leak() // function with memory leak
{
int* ptr = new int(5);
// body return without deallocating ptr
return;
}
int main()
{
// Call the functionto get the memory leak
func_to_show_mem_leak();
return 0;
}
Practice Tasks