BCS306B Module 2
Module – 2 Arrays, Pointers, References and the Dynamic Allocation
Operators
Arrays
In C++, arrays are collections of elements of the same data type, stored in contiguous memory locations.
Each element is accessed using an index (starting from 0).
Different Array Types
One-Dimensional Arrays
Two-Dimensional Arrays
Multidimensional Arrays
Character Arrays (Strings)
Array of Objects
Dynamic arrays
1) One-Dimensional Arrays : One Index. Stores data linearly
type array_name[size];
int marks[5] = {90, 85, 88, 92, 95};
2) Two-Dimensional Arrays: Two indices stores data in rows and columns
type array_name[rows][cols];
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
cout << matrix[1][2];
3) Character Arrays (Strings)
Array of characters ending with null (‘\0’).
Example:
char name[10] = "Sakshi";
cout << name; // prints Sakshi
4) Arrays can also store objects of a class.:
class Student {
public:
string name;
int age;
};
Student s[2] = {{"Amit", 20}, {"Neha", 21}};
cout << s[1].name; // prints Neha
Arrays of Objects
Just as we can create arrays of basic types (like int, float), we can also create arrays of class objects.
An array of objects helps in storing and processing a group of similar objects together.
Example: To maintain details of 50 students, instead of creating 50 separate objects, we create an array of 50
Student objects.
Syntax
class ClassName
{
// data members
// member functions
};
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 1
BCS306B Module 2
ClassName obj[size]; // array of objects
Here obj is the array name.
Each obj[i] is an object of ClassName.
Eg: program to create array of students.
#include <iostream>
using namespace std;
class Student {
int rollno;
string name;
public:
void getData()
{
cout << "Enter Roll No and Name: ";
cin >> rollno >> name;
}
void display()
{
cout << "Roll No: " << rollno << "\tName: " << name << endl;
}
};
int main()
{
Student s[3]; // array of 3 objects
cout << "Enter details of 3 students:\n";
for (int i = 0; i < 3; i++)
{
s[i].getData();
}
cout << "\nStudent Details:\n";
for (int i = 0; i < 3; i++)
{
s[i].display();
}
return 0;
}
Explanation
Student s[3]; creates 3 Student objects – s[0], s[1], s[2].
Each object stores its own data members (rollno, name).
Member functions are accessed using:
s[i].getData();
s[i].display();
When there is parameterized constructor in a class we need to initialize each object in an array by specifying an
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 2
BCS306B Module 2
initialization list.
For Eg: when we have a constructor with on e parameter we can initialize array of object as
Student(int r)
{rno=r;}
Array of objects can be initialized as normal array initialization as Student s[3]={23,45,56} this is called as
shorthand initialization. The actual initialization syntax is
Student s[3]= { Student(23),Student(45),Student(56)}
For Example if we have a constructor with more that one parameter then we need to initialize it with proper syntax as
Student(string n, int m) {
name = n;
marks = m;
}
Then while creating array of objects in main() we need to initialize objects as
Student s[3] = {
Student("Rahul", 85),
Student("Priya", 92),
Student("Amit", 76)
};
Pointers to Objects
A pointer to an object is similar to a pointer to a normal variable.
Instead of holding the address of a primitive type, it holds the address of an object.
Using pointers, we can dynamically access and manipulate objects.
Syntax
ClassName object;
ClassName *ptr; // pointer to class
ptr = &object; // store address of object
To access members of the object through a pointer:
Use arrow operator (->) instead of dot (.).
ptrmemberFunction();
Eg: Demonstrates pointer to single object
#include <iostream>
using namespace std;
class Student {
int roll;
char name[20];
public:
void getData() {
cout << "Enter Roll No and Name: ";
cin >> roll >> name;
}
void display()
{
cout << "Roll: " << roll << ", Name: " << name << endl;
}
};
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 3
BCS306B Module 2
int main()
{
Student s; // normal object
Student *ptr; // pointer to object
ptr = &s; // assign address of object
ptr->getData(); // access members using arrow operator
ptr->display();
return 0;
}
Objects can also be created dynamically using new as
Student *p=new Student;
pointer to array of objects : We can also set pointer to array of objects.
array name always contains base address of first object.
p = s; →set pointer to first object.
Increment pointer to move to next objects. p++
Eg: Demonstrates pointer to array of objects
#include <iostream>
using namespace std;
class Student {
int id;
string name;
public:
Student(int i, string n) {
id = i;
name = n;
}
void display() {
cout << "ID: " << id << ", Name: " << name << endl;
}
};
int main() {
//int n = 3;
Student s[3]={ Student(2,"hh"), Student(4,"mm"), Student(6,"ff")}; // normal array of objects initialized with
parameterized consructor
Student *p;
p=s; // pointer points to 1st object
cout << "\nStudent Details:\n";
for (int i = 0; i < 3; i++) {
p->display(); // display current object
p++; // move pointer to next object
}
return 0;
}
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 4
BCS306B Module 2
Advantages of Pointers to Objects
Advantages of Pointers to Objects
1. Dynamic Memory Management
o Allows creating objects at runtime using new.
o Useful when the number of objects is not known at compile time.
2. Efficient Memory Usage
o Only one pointer is stored, rather than copying whole objects.
o Reduces memory overhead when passing objects to functions.
3. Accessing Arrays of Objects Easily
o Pointers can traverse arrays of objects using p++ or p[i].
o Simplifies code for loops and dynamic arrays.
4. Supports Polymorphism
o Base class pointers can point to derived class objects.
o Enables runtime polymorphism with virtual functions.
5. Pass by Reference Behavior
o Using pointers allows modifying the original object inside functions.
o Avoids copying large objects unnecessarily.
6. Flexibility with Data Structures
o Essential for linked lists, trees, and other dynamic data structures using objects.
o
The “this” pointer
Every object in C++ has a special pointer called this.
When a member function is called an implicit pointer is passed automatically with an invoking
object. This implicit pointer is called “this” pointer
this contains the address of the object that invoked the member function.
It always points to the object that invoked the function.
We can return current object directly. (return *this)
Pass current object as argument to another function.
It is used to resolve Ambiguity between member variable and parameters with same variable name.
Eg:
class Test {
int a;
public:
void setA(int x) {
a = x; // assigns parameter x to data member a (it is same as writing thisa=x);
}
void show() {
cout << "a = " << a << endl;
}
};
Example – Resolving Ambiguity when data member and parameter has same
name
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 5
BCS306B Module 2
Example
#include <iostream>
using namespace std;
class Test {
int a;
public:
void setA(int a) {
this->a = a; // disambiguates data member from parameter
}
void show() {
cout << "a = " << a << endl;
}
};
int main() {
Test t;
[Link](42);
[Link]();
return 0;
}
Output:
a = 42
Without this, the compiler would not know whether ‘a’ refers to the member variable or the parameter.
If the parameter name is different from the data member → a = x; is enough.
If the parameter name is the same as the member → you must use this->a = a;.
Pointers to derived types
In general pointer of one type cannot point to object of a different type. But we can make base class
pointer to point to derived class object.
A derived class is a class that inherits from a base class.
Base class pointer can point to both base and derived objects (with some restrictions). But base
class pointer cannot access members added by derived class directly . For this we need to do
typecasting of base pointer to derived pointer or use virtual functions.
Derived class pointer can only point to derived objects.
Useful for dynamic polymorphism
Syntax
BaseClass *ptr; // pointer to base class
DerivedClass obj;
ptr = &obj; // base class pointer can point to derived object
Example – Base Pointer to Derived Object
#include <iostream>
using namespace std;
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 6
BCS306B Module 2
class Base {
public:
void showBase() {
cout << "Base class function\n";
}
};
class Derived : public Base {
public:
void showDerived() {
cout << "Derived class function\n";
}
};
int main() {
Derived d;
Base *ptr; // pointer to Base class
ptr = &d; // base pointer points to derived object
ptr->showBase(); // allowed
((Derived*)ptr)->showDerived(); // allowed with type casting. Convert base class pointer to
derived
}
Output:
Base class function
Derived class function
Pointers to class members
In C++, you can have pointers that point to members of a class (data members or member
functions).
These are not ordinary pointers; they need a specific object to be used.
Syntax differs slightly from normal pointers.
Access via .* or ->* operators.
Syntax
(i) Pointer to Data Member
type ClassName::*ptr;
ptr = &ClassName::dataMember;
(ii) Pointer to Member Function
returnType (ClassName::*ptr)(parameterList);
ptr = &ClassName::memberFunction;
To access via object:
object.*ptr // for object
objectPtr->*ptr // for pointer to object
3. Example – Pointer to Data Member
#include <iostream>
using namespace std;
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 7
BCS306B Module 2
class Test {
public:
int a;
};
int main() {
Test t;
int Test::*ptr = &Test::a; // pointer to data member 'a'
t.*ptr = 10; // access data member via object
cout << "a = " << t.*ptr << endl;
return 0;
}
Output:
a = 10
4. Example – Pointer to Member Function
#include <iostream>
using namespace std;
class Test {
public:
void show(int x) {
cout << "Value = " << x << endl;
}
};
int main() {
Test t;
void (Test::*ptr)(int) = &Test::show; // pointer to member function
(t.*ptr)(100); // call function via object
return 0;
}
Output:
Value = 100
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 8
BCS306B Module 2
Module2 – Function Overloading, Copy Constructors
Function Overloading
Function overloading allows multiple functions to have the same name but differ in the number of
parameters or type of their parameters. This enables a single function name to perform different tasks
based on the arguments passed. This is known as function polymorphism in OOP.
The compiler differentiates overloaded functions based on their signatures, which include the function
name, number of parameters, and types of parameters. The return type is not considered part of the
function signature for overloading purposes.
Function overloading is a form of compile-time polymorphism, where the decision about which function
to call is made at compile time based on the function signature.
Rules for Function Overloading
1. Different Parameter List
o The functions must differ in either:
Number of parameters or
Type of parameters or
Sequence of parameters
2. Same Scope
o Overloaded functions must be in the same class or global scope.
3. Return Type Alone Is Not Sufficient
o Functions cannot be distinguished only by return type.
In function overloading function must differ in regard to the types and / or number of parameters.
Two functions differing only in their return types cannot be overloaded.
For Eg;
int myfunc(int i);
float myfunc(int i);
Ex. On function overloading
#include <iostream>
using namespace std;
int add(int,int);
int add(int,int,int);
double add(double,double);
int add(int a, int b) //prototype1
{
return a + b;
}
double add(double a, double b) //prototype 2
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 9
BCS306B Module 2
{
return a + b;
}
int add(int a, int b, int c) //prototype 3
return a + b + c;
}
int main()
{
cout << "Sum of 2 integers: " << add(5, 10) << endl; //uses prototype1
cout << "Sum of 2 doubles: " << add(3.5, 4.1) << endl; //uses prototype2
cout << "Sum of 3 integers: " << add(1, 2, 3) << endl; //uses prototype3
return 0;
}
Output:
Sum of 2 integers: 15
Sum of 2 doubles: 7.6
Sum of 3 integers: 6
Function Overloading and Ambiguity:
Overloading can lead to ambiguity if the compiler is unable to choose between two or more overloaded
functions.
Type conversion ambiguity
C++ automatically does type conversion in to the type of arguments function required.
Ambiguity happens when multiple overloaded functions could be matched after implicit type conversion.
For Eg; in following code
int myfunc(double d);
cout << myfunc('c'); // not an error
'c' is a char, but C++ automatically converts it to double.
So it calls myfunc(double). No ambiguity here.
Ambiguity Between float and double :
float myfunc(float i);
double myfunc(double i);
int main() {
cout << myfunc(10.1); // calls double version (unambiguous). By default all floating constants are
double
cout << myfunc(10); // ambiguous ❌
}
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 1
0
BCS306B Module 2
10.1 → by default a double constant, so clearly calls myfunc(double).
10 → is an int. It can be converted to either float or double.
Compiler doesn’t know which one to choose so ambiguity happens
Reference vs Value Ambiguity
void f(int x);
void f(int &x); // error
int main() {
int a = 10;
f(a); // which one? ❌
}
Both functions look the same to the compiler, because whether you pass a as value or reference,
the call f(a) looks identical.
Hence, not allowed → compiler error.
Default Arguments ambiguity
A default argument in C++ is a parameter value specified in a function declaration. If the caller omits
that argument, the compiler automatically uses the default value.
For Eg: Mixing default arguments with overloaded functions can cause ambiguity.
void test(int a);
void test(int a, int b = 5);
test(4,5) // here two arguments are specified so no confusion it will call test(inta,intb)
test(10); // Error: ambiguous call—because compiler does not know whether to call first
version that takes one argument or to apply default to the version that takes two arguments.
Overloading Constructor Functions
Refer first module notes.
Copy Constructors:
Refer first module notes.
Default arguments
A default argument is a value given in the function declaration which is automatically used by the
compiler if the caller does not provide that argument.
Eg:
#include <iostream>
using namespace std;
void greet(string name = "Guest", int age = 18)
{
cout << "Name: " << name << ", Age: " << age << endl;
}
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 1
1
BCS306B Module 2
int main()
{
greet(); // Name: Guest, Age: 18
greet("Sakshi"); // Name: Sakshi, Age: 18
greet("Rahul", 25); // Name: Rahul, Age: 25
}
Rules of Default Arguments
Rules of Default Arguments
1. Defaults must be assigned from right to left.
void fun(int a, int b = 5, int c = 10); // ✅ Allowed
void fun(int a = 5, int b, int c = 10); // ❌ Not allowed
2. Defaults are given in the declaration or in the definition.
void show(int x = 10, int y = 20); // declaration with defaults
void show(int x, int y)
{ // definition (no defaults)
cout << x << " " << y;
}
Or
void show(int x=10, int y=20) //in definition
{
cout << x << " " << y;
}
3. Arguments are substituted left-to-right.
show(); // x = 10, y = 20
show(5); // x = 5, y = 20
show(5, 15); // x = 5, y = 15
4. Ambiguity with Overloading – If overloaded functions + defaults exist, compiler may get
confused.
void test(int a);
void test(int a, int b = 5);
test(10); // ❌ Ambiguous: both functions match
Advantages
1)Function Flexibility
A single function can work with different numbers of arguments.
Example:
void display(string name = "Guest");
display(); // uses default
display("Sakshi"); // uses user value
2)Reduces Function Overloading
Without defaults, you would need multiple overloaded versions of a function.
With defaults, one function can replace many.
Example (without defaults):
void show(int a);
void show(int a, int b);
void show(int a, int b, int c);
Example (with defaults):
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 1
2
BCS306B Module 2
void show(int a, int b = 0, int c = 0);
3. Improves Readability
o The function prototype itself shows what values will be used if the caller omits
arguments.
o Makes the code easier to understand.
4. Saves Coding Effort
o No need to write duplicate logic in multiple overloaded functions.
o Less code → fewer bugs, easier maintenance.
5. Backward Compatibility
o You can extend an existing function with new parameters (by giving them default
values) without breaking old function calls.
Default arguments vs function overloading
often default arguments can replace function overloading when the functionality is same.
Some times default arguments can provide alternative to function overloading.
Without defaults, you would need multiple overloaded versions of a function.
With defaults, one function can replace many.
For Eg:
Using Function Overloading
#include <iostream>
using namespace std;
void greet(string name)
{
cout << "Hello, " << name << "!" << endl;
}
void greet(string name, string message)
{
cout << message << ", " << name << "!" << endl;
}
int main()
{
greet("Sakshi"); // Hello, Sakshi!
greet("Sakshi", "Good Morning"); // Good Morning, Sakshi!
return 0;
}
Using Default Arguments (Alternative)
#include <iostream>
using namespace std;
void greet(string name, string message = "Hello")
{
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 1
3
BCS306B Module 2
cout << message << ", " << name << "!" << endl;
}
int main()
{
greet("Sakshi"); // uses default "Hello"
greet("Sakshi", "Good Morning"); // overrides default
return 0;
}
Prof. Sakshi Joshi, Dept. of CSc & Engg, JCER ,Belagavi 1
4