UNIT-2
Pointers, Arrays, Dynamic allocation Operator
- Like array of other user-defined data types, an array of type class can also be created.
- The array of type class contains the objects of the class as its individual elements.
- Thus, an array of a class type is also known as an array of objects.
- An array of objects is declared in the same way as an array of any built-in data type.
class_name array_name [size] ;
#include <iostream>
class MyClass {
int x;
public:
void setX(int i) { x = i; }
int getX() { return x; }
};
void main()
{
MyClass obs[4];
int i;
for(i=0; i < 4; i++)
obs[i].setX(i);
for(i=0; i < 4; i++)
cout << "obs[" << i << "].getX(): " << obs[i].getX() << "\n";
getch();
}
Output:
obs[0].getX(): 0
obs[1].getX(): 1
obs[2].getX(): 2
obs[3].getX(): 3
Key takeaway
- Like array of other user-defined data types, an array of type class can also be created.
- The array of type class contains the objects of the class as its individual elements.
- Thus, an array of a class type is also known as an array of objects.
- An array of objects is declared in the same way as an array of any built-in data type.
A pointer to a C++ class is done exactly the same way as a pointer to a structure and to access members of a pointer to a class you use the member access operator -> operator, just as you do with pointers to structures. Also as with all pointers, you must initialize the pointer before using it.
Let us try the following example to understand the concept of pointer to a class −
#include <iostream>
using namespace std;
class Box {
public:
// Constructor definition
Box(double l = 2.0, double b = 2.0, double h = 2.0) {
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
}
double Volume() {
return length * breadth * height;
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
int main(void) {
Box Box1(3.3, 1.2, 1.5); // Declare box1
Box Box2(8.5, 6.0, 2.0); // Declare box2
Box *ptrBox; // Declare pointer to a class.
// Save the address of first object
ptrBox = &Box1;
// Now try to access a member using member access operator
cout << "Volume of Box1: " << ptrBox->Volume() << endl;
// Save the address of second object
ptrBox = &Box2;
// Now try to access a member using member access operator
cout << "Volume of Box2: " << ptrBox->Volume() << endl;
return 0;
}
When the above code is compiled and executed, it produces the following result −
Constructor called.
Constructor called.
Volume of Box1: 5.94
Volume of Box2: 102
Key takeaway
A pointer to a C++ class is done exactly the same way as a pointer to a structure and to access members of a pointer to a class you use the member access operator -> operator, just as you do with pointers to structures. Also as with all pointers, you must initialize the pointer before using it.
Every object in C++ has access to its own address through an important pointer called this pointer. The this pointer is an implicit parameter to all member functions. Therefore, inside a member function, this may be used to refer to the invoking object.
Friend functions do not have a this pointer, because friends are not members of a class. Only member functions have a this pointer.
Let us try the following example to understand the concept of this pointer −
#include <iostream>
using namespace std;
class Box {
public:
// Constructor definition
Box(double l = 2.0, double b = 2.0, double h = 2.0) {
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
}
double Volume() {
return length * breadth * height;
}
int compare(Box box) {
return this->Volume() > box.Volume();
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
int main(void) {
Box Box1(3.3, 1.2, 1.5); // Declare box1
Box Box2(8.5, 6.0, 2.0); // Declare box2
if(Box1.compare(Box2)) {
cout << "Box2 is smaller than Box1" <<endl;
} else {
cout << "Box2 is equal to or larger than Box1" <<endl;
}
return 0;
}
When the above code is compiled and executed, it produces the following result −
Constructor called.
Constructor called.
Box2 is equal to or larger than Box1
Key takeaway
Every object in C++ has access to its own address through an important pointer called this pointer. The this pointer is an implicit parameter to all member functions. Therefore, inside a member function, this may be used to refer to the invoking object.
Friend functions do not have a this pointer, because friends are not members of a class. Only member functions have a this pointer.
C++ pointers are easy and fun to learn. Some C++ tasks are performed more easily with pointers, and other C++ tasks, such as dynamic memory allocation, cannot be performed without them.
As you know every variable is a memory location and every memory location has its address defined which can be accessed using ampersand (&) operator which denotes an address in memory. Consider the following which will print the address of the variables defined −
#include <iostream>
using namespace std;
int main () {
int var1;
char var2[10];
cout << "Address of var1 variable: ";
cout << &var1 << endl;
cout << "Address of var2 variable: ";
cout << &var2 << endl;
return 0;
}
When the above code is compiled and executed, it produces the following result −
Address of var1 variable: 0xbfebd5c0
Address of var2 variable: 0xbfebd5b6
A pointer is a variable whose value is the address of another variable. Like any variable or constant, you must declare a pointer before you can work with it. The general form of a pointer variable declaration is −
type *var-name;
Here, type is the pointer's base type; it must be a valid C++ type and var-name is the name of the pointer variable. The asterisk you used to declare a pointer is the same asterisk that you use for multiplication. However, in this statement the asterisk is being used to designate a variable as a pointer. Following are the valid pointer declaration −
int *ip; // pointer to an integer
double *dp; // pointer to a double
float *fp; // pointer to a float
char *ch // pointer to character
The actual data type of the value of all pointers, whether integer, float, character, or otherwise, is the same, a long hexadecimal number that represents a memory address. The only difference between pointers of different data types is the data type of the variable or constant that the pointer points to.
There are few important operations, which we will do with the pointers very frequently. (a) We define a pointer variable. (b) Assign the address of a variable to a pointer. (c) Finally access the value at the address available in the pointer variable. This is done by using unary operator * that returns the value of the variable located at the address specified by its operand. Following example makes use of these operations −
#include <iostream>
using namespace std;
int main () {
int var = 20; // actual variable declaration.
int *ip; // pointer variable
ip = &var; // store address of var in pointer variable
cout << "Value of var variable: ";
cout << var << endl;
// print the address stored in ip pointer variable
cout << "Address stored in ip variable: ";
cout << ip << endl;
// access the value at the address available in pointer
cout << "Value of *ip variable: ";
cout << *ip << endl;
return 0;
}
When the above code is compiled and executed, it produces result something as follows −
Value of var variable: 20
Address stored in ip variable: 0xbfc601ac
Value of *ip variable: 20
Pointers have many but easy concepts and they are very important to C++ programming. There are following few important pointer concepts which should be clear to a C++ programmer −
Sr.No | Concept & Description |
1 | Null Pointers C++ supports null pointer, which is a constant with a value of zero defined in several standard libraries. |
2 | Pointer Arithmetic There are four arithmetic operators that can be used on pointers: ++, --, +, - |
3 | Pointers vs Arrays There is a close relationship between pointers and arrays. |
4 | Array of Pointers You can define arrays to hold a number of pointers. |
5 | Pointer to Pointer C++ allows you to have pointer on a pointer and so on. |
6 | Passing Pointers to Functions Passing an argument by reference or by address both enable the passed argument to be changed in the calling function by the called function. |
7 | Return Pointer from Functions C++ allows a function to return a pointer to local variable, static variable and dynamically allocated memory as well. |
Key takeaway
C++ pointers are easy and fun to learn. Some C++ tasks are performed more easily with pointers, and other C++ tasks, such as dynamic memory allocation, cannot be performed without them.
As you know every variable is a memory location and every memory location has its address defined which can be accessed using ampersand (&) operator which denotes an address in memory.
Data types are means to identify the type of data and associated operations of handling it. There are three types of data types:
- Derived Data Types
- Pre-defined Data Types
- User-defined Data Types
Fig 1 – DataTypes
In this article, the Derived Data Type is explained:
The data-types that are derived from the primitive or built-in datatypes are referred to as Derived Data Types. These can be of four types namely:
- Function
- Array
- Pointers
- References
Let’s briefly understand each of the following derived datatypes:
- Function: A function is a block of code or program-segment that is defined to perform a specific well-defined task. A function is generally defined to save the user from writing the same lines of code again and again for the same input. All the lines of code are put together inside a single function and this can be called anywhere required. main() is a default function that is defined in every program of C++.
Syntax:
FunctionType FunctionName(parameters)
Example:
// C++ program to demonstrate // Function Derived Type
#include <iostream> using namespace std;
// max here is a function derived type int max(int x, int y) { if (x > y) return x; else return y; }
// main is the default function derived type int main() { int a = 10, b = 20;
// Calling above function to // find max of 'a' and 'b' int m = max(a, b);
cout << "m is " << m; return 0; } |
Output:
m is 20
2. Array: An array is a collection of items stored at continuous memory locations. The idea of array is to represent many instances in one variable.
Fig 2 – Example
Syntax:
DataType ArrayName[size_of_array];
Example:
// C++ program to demonstrate // Array Derived Type
#include <iostream> using namespace std; int main() {
// Array Derived Type int arr[5]; arr[0] = 5; arr[2] = -10;
// this is same as arr[1] = 2 arr[3 / 2] = 2;
arr[3] = arr[0];
cout<<arr[0]<<" "<<arr[1]<<" "<<arr[2]<<" "<<arr[3];
return 0; } |
Output:
5 2 -10 5
3. Pointers: Pointers are symbolic representation of addresses. They enable programs to simulate call-by-reference as well as to create and manipulate dynamic data structures. It’s general declaration in C/C++ has the format:
Syntax:
datatype *var_name;
Example:
int *ptr;
ptr points to an address
which holds int data
Example:
// C++ program to illustrate // Pointers Derived Type
#include <bits/stdc++.h> using namespace std;
void geeks() { int var = 20;
// Pointers Derived Type // declare pointer variable int* ptr;
// note that data type of ptr // and var must be same ptr = &var;
// assign the address of a variable // to a pointer cout << "Value at ptr = " << ptr << "\n"; cout << "Value at var = " << var << "\n"; cout << "Value at *ptr = " << *ptr << "\n"; }
// Driver program int main() { geeks(); } |
Output:
Value at ptr = 0x7ffc10d7fd5c
Value at var = 20
Value at *ptr = 20
4. Reference: When a variable is declared as reference, it becomes an alternative name for an existing variable. A variable can be declared as reference by putting ‘&’ in the declaration.
Example:
// C++ program to illustrate // Reference Derived Type
#include <iostream> using namespace std;
int main() { int x = 10;
// Reference Derived Type // ref is a reference to x. int& ref = x;
// Value of x is now changed to 20 ref = 20; cout << "x = " << x << endl;
// Value of x is now changed to 30 x = 30; cout << "ref = " << ref << endl;
return 0; } |
Output:
x = 20
ref = 30
Key takeaway
Data types are means to identify the type of data and associated operations of handling it. There are three types of data types:
- Derived Data Types
- Pre-defined Data Types
- User-defined Data Types
A pointer to a C++ class is done exactly the same way as a pointer to a structure and to access members of a pointer to a class you use the member access operator -> operator, just as you do with pointers to structures. Also as with all pointers, you must initialize the pointer before using it.
Let us try the following example to understand the concept of pointer to a class –
#include <iostream>
using namespace std;
class Box {
public:
// Constructor definition
Box(double l = 2.0, double b = 2.0, double h = 2.0) {
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
}
double Volume() {
return length * breadth * height;
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
int main(void) {
Box Box1(3.3, 1.2, 1.5); // Declare box1
Box Box2(8.5, 6.0, 2.0); // Declare box2
Box *ptrBox; // Declare pointer to a class.
// Save the address of first object
ptrBox = &Box1;
// Now try to access a member using member access operator
cout << "Volume of Box1: " << ptrBox->Volume() << endl;
// Save the address of second object
ptrBox = &Box2;
// Now try to access a member using member access operator
cout << "Volume of Box2: " << ptrBox->Volume() << endl;
return 0;
}
When the above code is compiled and executed, it produces the following result −
Constructor called.
Constructor called.
Volume of Box1: 5.94
Volume of Box2: 102
Key takeaway
A pointer to a C++ class is done exactly the same way as a pointer to a structure and to access members of a pointer to a class you use the member access operator -> operator, just as you do with pointers to structures. Also as with all pointers, you must initialize the pointer before using it.
A good understanding of how dynamic memory really works in C++ is essential to becoming a good C++ programmer. Memory in your C++ program is divided into two parts −
- The stack − All variables declared inside the function will take up memory from the stack.
- The heap − This is unused memory of the program and can be used to allocate the memory dynamically when program runs.
Many times, you are not aware in advance how much memory you will need to store particular information in a defined variable and the size of required memory can be determined at run time.
You can allocate memory at run time within the heap for the variable of a given type using a special operator in C++ which returns the address of the space allocated. This operator is called new operator.
If you are not in need of dynamically allocated memory anymore, you can use delete operator, which de-allocates memory that was previously allocated by new operator.
There is following generic syntax to use new operator to allocate memory dynamically for any data-type.
new data-type;
Here, data-type could be any built-in data type including an array or any user defined data types include class or structure. Let us start with built-in data types. For example we can define a pointer to type double and then request that the memory be allocated at execution time. We can do this using the new operator with the following statements −
double* pvalue = NULL; // Pointer initialized with null
pvalue = new double; // Request memory for the variable
The memory may not have been allocated successfully, if the free store had been used up. So it is good practice to check if new operator is returning NULL pointer and take appropriate action as below −
double* pvalue = NULL;
if( !(pvalue = new double )) {
cout << "Error: out of memory." <<endl;
exit(1);
}
The malloc() function from C, still exists in C++, but it is recommended to avoid using malloc() function. The main advantage of new over malloc() is that new doesn't just allocate memory, it constructs objects which is prime purpose of C++.
At any point, when you feel a variable that has been dynamically allocated is not anymore required, you can free up the memory that it occupies in the free store with the ‘delete’ operator as follows −
delete pvalue; // Release memory pointed to by pvalue
Let us put above concepts and form the following example to show how ‘new’ and ‘delete’ work −
#include <iostream>
using namespace std;
int main () {
double* pvalue = NULL; // Pointer initialized with null
pvalue = new double; // Request memory for the variable
*pvalue = 29494.99; // Store value at allocated address
cout << "Value of pvalue : " << *pvalue << endl;
delete pvalue; // free up the memory.
return 0;
}
If we compile and run above code, this would produce the following result −
Value of pvalue : 29495
Dynamic Memory Allocation for Arrays
Consider you want to allocate memory for an array of characters, i.e., string of 20 characters. Using the same syntax what we have used above we can allocate memory dynamically as shown below.
char* pvalue = NULL; // Pointer initialized with null
pvalue = new char[20]; // Request memory for the variable
To remove the array that we have just created the statement would look like this −
delete [] pvalue; // Delete array pointed to by pvalue
Following the similar generic syntax of new operator, you can allocate for a multi-dimensional array as follows −
double** pvalue = NULL; // Pointer initialized with null
pvalue = new double [3][4]; // Allocate memory for a 3x4 array
However, the syntax to release the memory for multi-dimensional array will still remain same as above −
delete [] pvalue; // Delete array pointed to by pvalue
Dynamic Memory Allocation for Objects
Objects are no different from simple data types. For example, consider the following code where we are going to use an array of objects to clarify the concept −
#include <iostream>
using namespace std;
class Box {
public:
Box() {
cout << "Constructor called!" <<endl;
}
~Box() {
cout << "Destructor called!" <<endl;
}
};
int main() {
Box* myBoxArray = new Box[4];
delete [] myBoxArray; // Delete array
return 0;
}
If you were to allocate an array of four Box objects, the Simple constructor would be called four times and similarly while deleting these objects, destructor will also be called same number of times.
If we compile and run above code, this would produce the following result −
Constructor called!
Constructor called!
Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!
Key Takeaway
A good understanding of how dynamic memory really works in C++ is essential to becoming a good C++ programmer. Memory in your C++ program is divided into two parts −
- The stack − All variables declared inside the function will take up memory from the stack.
- The heap − This is unused memory of the program and can be used to allocate the memory dynamically when program runs.
REFERENCE
1 Object-Oriented Programming with C++ by E. Balaguruswamy. (Tata McGraw-Hill) 6th Edition and onwards
2. Object oriented Programming with C++- by SouravSahay (Oxford) 2ndedition