Week10 - 4
Week10 - 4
Pointers in C++
BS (SE) Fall-2024
1
Agenda
▪ Introduction pointers
▪ Getting the address of a variable
▪ Pointer variables
▪ The relationship between arrays and pointers
▪ Pointer arithmetic
▪ Initializing pointers
▪ Comparing pointers
▪ Types of pointer variables
▪ Dynamic memory allocation.
▪ Array of pointers
2
Getting the Address of a Variable
▪ Each variable in program is stored at a unique address
▪ Use address operator & to get address of a variable:
int num = -99;
cout << # // prints address
// in hexadecimal
3
Pointer Variables
▪ Pointer variable : Often just called a pointer, it's a variable that holds an address
▪ Because a pointer variable holds the address of another piece of data, it "points"
to the data
▪ We have already worked with something similar to pointers, when we learned to
pass arrays as arguments to functions.
▪ For example, suppose we use this statement to pass the array numbers to the
showValues function:
showValues(numbers, SIZE);
4
Pointer Variables (definition)
▪ Pointer variables are yet another way using a memory address to work with a
piece of data.
▪ Pointers are more "low-level" than arrays and reference variables.
▪ This means you are responsible for finding the address you want to store in the
pointer and correctly using it.
▪ Declaration:
int *intptr;
▪ Read as:
“intptr can hold the address of an int” or “the variable that intptr points
to has type int”
5
Purpose of Pointer
▪ 1. Dynamic Memory Allocation
▪ 2. Linked Data Structures
▪ 3. Polymorphism (Runtime Binding)
▪ 4. Callbacks and Function Pointers
▪ 5. Accessing Hardware Resources
▪ 6. Sharing Data Across Functions
6
Initializing Pointers
▪ Can initialize at definition time:
int num, *numptr = #
int val[3], *valptr = val;
▪ Cannot mix data types:
double cost;
int *ptr = &cost; // won’t work
▪ Can test for an invalid address for ptr with:
if (!ptr) ...
7
Pointer Variables (declaration and definition)
▪ Spacing in definition does not matter:
int * intptr; // same as above
int* intptr; // same as above
▪ nullptr represent the address 0 and supported only in the C++ 11 standard
and above)
▪ OR we can also initialize it with 0 or NULL
intptr = 0; or intptr = NULL; (if you are using older version of
C++ compiler)
8
Pointer Variables (address assignment)
▪ Assigning an address to a pointer variable:
int *intptr;
intptr = #
▪ Memory layout
num intptr
0x4a00
address of num: 0x4a00
9
Example program
10
The Indirection Operator
▪ The indirection operator (*) dereferences a pointer.
▪ It allows you to access the item that the pointer points to.
int x = 25;
int *intptr = &x;
cout << *intptr << endl;
11
Example program
12
Example program
#include<iostream>
using namespace std;
int main()
{
int a = 10;
cout << "a: " << a << endl;
cout << "&a: " << &a << endl;
int* ptr = &a;
Output:
cout << "ptr: " << ptr << endl;
a: 10
cout << "*ptr: " << *ptr << endl;
&a: 0x61ff0c
cout << "&ptr: " << &ptr << endl; ptr: 0x61ff0c
int** ptr1 = &ptr; *ptr: 10
cout << "*ptr1: " << *ptr1 << endl; &ptr: 0x61ff08
cout << "**ptr1: " << **ptr1; *ptr1: 0x61ff08
return 0; **ptr1: 10
}
13
Passing arguments (calling a function)
▪ Pass-by-value (recap)
• Send the copy of the values of arguments
• can not modify original values of the arguments
▪ Pass-by-reference with reference arguments (recap)
• Arguments passed to function using reference arguments
• Modify original values of the arguments
▪ Pass-by-reference with pointer arguments
• Simulate pass-by-reference
• Use pointers and indirection operator
• Pass address of argument using & operator
14
Example (arguments pass by value)
Output:
The original value of number is =5
The cube of the number is = 125
The original value of number after call by value is = 5
15
Example (arguments pass by reference)
Output:
The original value of number is =5
The cube of the number is = 125
The original value of number after call by reference is = 125
16
Example (Pass by reference with pointers)
Output:
The original value of number is =5
The cube of the number is = 125
The original value of number after call by reference using pointers is = 125 17
Something Like Pointers (Arrays)
18
Something Like Pointers (Reference Variables)
▪ We have also worked with something like pointers when we learned to use
reference variables. Suppose we have this function:
19
Something Like Pointers (Reference Variables)
The donuts parameter, in the getOrder function,
points to the jellyDonuts variable.
20
The Relationship Between Arrays and Pointers
▪ Array name is starting address of array
4 7 11
int vals[] = {4, 7, 11}; starting address of vals: 0x4a00
cout << vals; // displays: 0x4a00
cout << vals[0]; // displays 4
21
Example program
22
Pointers in Expressions
Given:
int vals[]={4,7,17}, *valptr;
valptr = vals;
What is valptr + 1?
//It means (address in valptr) + (1 * size of an int)
cout << *(valptr+1); //displays 7
cout << *(valptr+2); //displays 17
23
Array Access
▪ Array elements can be accessed in many ways: e.g., int vals[]={4,7,17},
24
Example program
25
Pointer Arithmetic
▪ Operations on pointer variables:
26
Example program
27
Example program
#include<iostream>
using namespace std;
int main(){
int a=10;
int *ptr = &a;
cout<<"a ="<<a<<endl;
cout<<"ptr ="<<ptr<<endl; a =10
cout<<"&a ="<<&a<<endl; ptr =0x78febc
cout<<"*ptr ="<<*ptr<<endl; &a =0x78febc
*ptr =10
cout<<"&ptr ="<<&ptr<<endl; &ptr =0x78feb8
cout<<"*&ptr ="<<*&ptr<<endl; *&ptr =0x78febc
cout<<"&*ptr ="<<&*ptr<<endl; &*ptr =0x78febc
}
28
Comparing Pointers
▪ Relational operators (<, >=, etc.) can be used to compare addresses in pointers
▪ Comparing addresses in pointers is not the same as comparing contents pointed
at by pointers:
if (ptr1 == ptr2) // compares addresses
if (*ptr1 == *ptr2) // compares contents
29
Pointers as Function Parameters
▪ A pointer can be a parameter
▪ Works like reference variable to allow change to argument from
within function
▪ Requires:
1) asterisk * on parameter in prototype and heading
void getNum(int *ptr); // ptr is pointer to an int
2) asterisk * in body to dereference the pointer
cin >> *ptr;
3) address as argument to the function
getNum(&num); // pass address of num to getNum
30
Example program
void swap(int *x, int *y)
{ int temp;
temp = *x;
*x = *y;
*y = temp;
}
31
Example program
32
Types of Pointer variables (Type1)
▪ Non-constant pointer with non-constant data
• The pointer variable and data both can be changed
33
//non-constant pointer (ptr) with non-constant data (*ptr)
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = 50;
int* ptra = 0;
ptra = &a;
cout << "ptra value = " << ptra << endl;
cout << "*ptra value = " << *ptra << endl;
*ptra = 30;
cout << "ptra value = " << ptra << endl;
cout << "*ptra value = " << *ptra << endl; Output:
ptra value = 0x61ff04
ptra = &b;
cout << "ptra value = " << ptra << endl; *ptra value = 10
cout << "*ptra value = " << *ptra << endl; ptra value = 0x61ff04
*ptra = 30;
*ptra value = 30
cout << "ptra value = " << ptra << endl; ptra value = 0x61ff00
cout << "*ptra value = " << *ptra << endl;
*ptra value = 50
int* ptrb = 0; ptra value = 0x61ff00
ptrb = &a;
cout << "ptrb value = " << ptrb << endl;
*ptra value = 30
cout << "*ptrb value = " << *ptrb << endl; ptrb value = 0x61ff04
*ptrb = 100;
*ptrb value = 30
cout << "ptrb value = " << ptrb << endl; ptrb value = 0x61ff04
cout << "*ptrb value = " << *ptrb << endl;
}
*ptrb value = 100
34
Types of Pointer variables (Type2)
▪ Constant pointer with non-constant data
• Pointer will remain constant while data can be changed
35
//constant pointer (ptr) with non-constant data (*ptr)
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = 50;
//int *ptr =0;
//ptr= &a;
int* const ptra = &a;
cout << "ptra value = " << ptra << endl;
cout << "*ptra value = " << *ptra << endl;
*ptra = 30;
cout << "ptra value = " << ptra << endl;
Output:
cout << "*ptra value = " << *ptra << endl;
ptra value = 0x61ff04
*ptra value = 10
ptra= &b; // this will not be allowed
ptra value = 0x61ff04
// cout << "ptr value = " << ptra << endl; *ptra value = 30
// cout << "*ptr value = " << *ptra << endl;
}
36
Types of Pointer variables (Type3)
▪ Non-constant pointer with constant data
• Pointer can be changed but the data will remain fixed
37
//non-constant pointer (ptr)with constant data (*ptr)
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = 50;
//int *ptr =0;
//ptr= &a;
const int* ptra = &a;
cout << "ptra value = " << ptra << endl;
cout << "*ptra value = " << *ptra << endl;
Output:
ptra value = 0x61ff08
ptra = &b; *ptra value = 10
cout << "ptra value = " << ptra << endl; ptra value = 0x61ff04
cout << "*ptra value = " << *ptra << endl; *ptra value = 50
*ptra = 30; // this will not be possible because data should be fixed.
// cout << "ptra value = " << ptra << endl;
// cout << "*ptra value = " << *ptra << endl;
}
38
Pointers to Constants
▪ If we want to store the address of a constant in a pointer, then we need to store
it in a pointer-to-const.
▪ Example: Suppose we have the following definitions:
39
Example program
void displayPayRates(const double *rates, int size)
{
for (int count = 0; count < size; count++)
{
cout << "Pay rate for employee " << (count + 1)
<< " is $" << *(rates + count) << endl;
}
} The parameter, rates, is a pointer to const double.
40
Types of Pointer variables (Type4)
▪ constant pointer with constant data
• Both the pointer and data will remain constant
41
//constant pointer (ptr)with constant data (*ptr)
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = 50;
▪ Example
43
Constant Pointers to Constants
▪ A constant pointer to a constant is:
• a pointer that points to a constant
• a pointer that cannot point to anything except what it is pointing to
▪ Example:
int value = 22;
const int * const ptr = &value;
44
Void pointers
▪ A void pointer has no associated data type with it
• A void pointer can hold address of any type and can be typcasted to any type
• void pointers cannot be dereferenced
▪ Example program:
#include<iostream>
using namespace std;
int main()
{
int a = 10; Output:
void* ptr = &a; The output of ptr :
cout << "The output of ptr : " << ptr; 0x61ff08
cout << *ptr; // dereferencing is not possible
return 0;
}
45
Void pointers
▪ void* is a pointer to no type at all:
• Any pointer type may be assigned to void *
int iVar=5;
float fVar=4.3;
char cVar=‘Z’;
int* p1;
void* vp2;
p1 = &iVar; // Allowed
p1 = &fvar; // Not Allowed
P1 = &cVar; // Not Allowed
vp2 = &fvar; // Allowed
vp2 = &cVar; // Allowed
vp2 = &iVar; // Allowed 46
Example program
#include<iostream>
using namespace std;
int main() {
int a = 10;
char b = 'x';
49
Example program (pointer to a pointer)
Output:
The value of a is = 5
The value of integer using dereferencing by pointer is = 5
The value integer by two time dereferencing using pointer is = 5 50
Example program2 (pointer to a pointer)
Output:
The address of iptr: 0x61ff04 or 0x61ff04
The address of x: 0x61ff08 or 0x61ff08 or 0x61ff08
The value of x: 5 or 5 or 5
51
Pointers and one-dimensional array (recap)
▪ Suppose we have a one-dimensional array of:
int A[]={5,7,9}; How pointers are used for one-dimensional array?
▪ Example: A[0] A[1] A[2]
Indexes of Array’ elements: A
int A[]={5,7,9};
int *ptr = A; Name of Array: A 5 7 9
cout<<A; //it will print 100
Base address of Array A is: 100 100 104 108
cout<<&A; //it will print 100
cout<<&A[0]; //it will print 100
cout<<ptr; //it will print 100
cout<<A+1; // it will print 104 Ptr
cout<<ptr + 1; it will print 104
100
cout<<A[0]; // it will print 5
cout<<*ptr; // it will print 5
cout<<A[1]; // it will print 7 Note:
cout<<*(ptr+1); // it will print 7 *(A +i) is same as A[i]
Note: cout<<*ptr+1; // it will print 6 (A +i) is same as &A[i]o
52
Two dimensional arrays and its representation
▪ An array is a contiguous block of memory
• A 2-D array of size x by y is defined as int A[x][y];
• The number of bytes necessary to hold A is x*y*sizeof(int)
• The elements of A can be accessed using A[i][j] (where i can be thought of as
the row index and j can be thought of as the column index)
▪ Example:
int A[2][3]={{5,7,9},{4,8,6}};
0 1 2
0 A[0][0] A[0][1] A[0][2]
(5) (7) (9)
Ptr2D
(Pointer to a Pointer)
Two dimensional arrays and its representation
▪ How 2-D arrays are store their elements in memory
▪ For example, int A[x][y];
• can be defined and initialized as
int A[2][3]={{5,7,9},{4,8,6}};
• Here x represents the number of rows and y represents the number of
columns
• The 2-D array is stored in memory as shown below:
In memory representation
55
Two dimensional arrays and pointers
▪ Creating two-dimensional array requires double pointers
Example:
int **ptr;
▪ Similarly, three-dimensional array requires triple pointers
Example:
int ***ptr;
▪ Example:
int A[2][3]={{5,7,9},{4,8,6}};
▪ So, A[2][3] is basically two 1-D arrays of 3 integers each.
▪ so, If we assign this array to pointer as follow, it will give us a compilation error:
int *P = A; // will not return a pointer to int it will return 1-D array of 3 integers
56
Two dimensional arrays and pointers
▪ The correct will be:
int (*p)[3] = A; // Declaring pointer to 1-D array of three integers
Examples: cout<<(*p)[0]; //will print 5
cout<<(*p)[4]; //will print 8
cout<<A; or cout<<&A[0]; //it will print 100
cout<<*A; or & A[0][0]; // all will print 100
cout<<A+1; //it will print 112
57
A [0] A [1]
Some more print statements
cout<<*(A + 1); or A[1] or &A[1][0] ; // all will print 112
cout<<*(A+1)+2; or A[1]+2; or &A[1][2] ; // it will print 120
cout<<*(*A+1); //will print value on address 104, which is 7.
cout<<*&A[0][1]; //will print value on address 104, which is 7.
or cout<<A[0][1]; //will print value on address 104, which is 7.
A [0] A [1]
58
Motivation (Dynamic memory allocation: DMA)
▪ Allocation of memory requested in declarations of variables and arrays etc.,
• Fixed size before the execution of the program
• The stack overflow can occur (e.g., due to bad recursions etc., )
• Allocation and deallocation on the stack is performed by set rules
• Manipulation of the scope of a variable not possible during run time
• Declaring a large data type (e.g., Array) as a local variable, needs static size on
the compile time and not possible to change the size at run time
▪ What if we need a variable amount of memory? That can only be determined
during the program execution (runtime)
• The answer is dynamic memory (allocation of memory from the heap)
• The programmer can allocate any size of memory from the heap
• Heap is a large free pool of memory on the RAM
• Four functions (malloc, calloc, realloc and free) used in C for memory
allocation on the heap
• C++ using the operators new for allocation and delete for deallocation
59
The problems with fixed size arrays
▪ Array declaration with a fixed size like int array[500000]; has two typical
problems
▪ Exceeding maximum
• Choosing a real maximum is often impossible because the programmer has no
control over the size of the data sets the user is interested in
• Erroneous assumptions that a maximum will never be exceeded are the source of
many programming bugs
• Declaring very large arrays can be extremely wasteful of memory, and if there are
many such arrays, may prevent the program from running in some systems
▪ No expansion
• Using a small size may be more efficient for the typical data set, but prevents the
program from running with larger data sets
• If array limits are not checked, large data sets will run over the end of an array
with disastrous consequences
• Fixed size arrays cannot expand as needed 60
The solution
▪ These two problems can be avoided by dynamically allocating an array of the
right size, or reallocating an array when it needs to expand
• Declare an array as a pointer and using the new operator to allocate memory
• Use delete operator to free memory that is no longer needed
61
Why use pointers as arrays?
▪ The size of an array must be a constant value
• Limits its size on designing stage of the program before its execution
• Dynamic memory allocation allows assigning memory during the execution of
the program using any variable, constant or combination of both
▪ Static memory allocation
• Automatically and statically assigned during the compile time on stack
▪ Dynamic memory
• Memory allocation perform on demand, dynamically at run time on the heap
• The dynamic memory is generally managed by the operating system and
shared between several applications
• Memory exhaustion is possible
• Operating system cannot assign the requested memory with the operator
new and a null pointer will be returned
• It is recommended to always check to see if the returned pointer is null after
a call to new
62
Arrays of pointers
▪ Uses of pointers to pointers
• The most common use is to dynamically allocate an array of pointers
• Example:
int **array = new int*[10]; // allocate an array of 10 int
pointers
• This works just like a standard dynamically allocated array, except the array
elements are of type “pointer to integer” instead of integer
63
Memory stack in C++
64
Memory allocation in c++ Heap
Sharable memory
65
Dynamic memory allocation
▪ Can allocate storage for a variable while program is running
• Uses new operator to allocate memory
• Example:
double *dptr;
dptr = new double;
• The new operator is used to request dynamic memory
• The new operator returns address of memory location
• The new operator is followed by a data type and optionally the number of elements required
within brackets []
• Returns a pointer to the beginning of the new block of assigned memory
• Syntax: pointer = new type; //to assign memory to contain one single
element of type
or
pointer = new type [elements]; //to assign a block (an array)
of elements of type
66
Example program (dynamic memory allocation for
a single variable)
Output:
The value in the memory is 20
67
Example (new operator for an array)
▪ Can also use new to allocate array
• Example: arrayPtr = new double[25];
• Program may terminate if there is not sufficient int * b;
memory
b = new int [5];
▪ Can then use [] or pointer arithmetic to access if (b == NULL)
array {
▪ Example: // error assigning memory.
// Take measures.
int * b;
b = new int[5];
▪ The operating system will assign space for 5 };
elements of type int in a heap
• And will return a pointer to its beginning
• That has been assigned to b
• Therefore, now, b points to a valid block of
memory with space for 5 int elements
b
68
Delete operator
▪ Once the dynamic memory is no longer needed it should be freed
▪ So that it becomes available for future requests of dynamic memory
▪ The operator delete exists for this purpose
delete pointer;
or
delete [] pointer;
• The first expression should be used to delete memory allocated for a single
element
• The second one for memory allocated for multiple elements (arrays)
• In most compilers both of these operators are equivalent
69
DMA for 1-D array
Output:
Please enter the size for array
5
100 101 102 103 104
70
DMA for 1-D array
Output:
100 101 102 103 104 105 106 107 108 109
71
Example program (DMA)
Output:
How many students? 5
Enter score 0: 20
Enter score 1: 50
Enter score 2: 100
Enter score 3: 50
Enter score 4: 40
72
Example program (DMA for 1-D array )
Output:
Please enter the size of the array: 5
Please enter the values for the array of size 5
value at index 0 = 2
value at index 1 = 5
value at index 2 = 3
value at index 3 = 8
value at index 4 = 9
Your values in the array are : 2 5 3 8 9
73
DMA for 2-D array)
Output:
Please enter values in 2-D Array :
5
7
8
5
9
4
5
6
1
2
3
8
4
6
2
2
The values entered in the 2-D array are :
5785
9456
1238
4622
74
Dangling pointers and memory leaks
▪ A pointer is dangling if it contains the address of memory that has been freed by
a call to delete
• Solution: set such pointers to 0 as soon as memory is freed
▪ A memory leak occurs if no-longer-needed dynamic memory is not freed
▪ The memory is unavailable for reuse within the program
• Solution: free up dynamic memory after use
75
Controlling memory leaks
▪ Memory that is allocated with new should be deallocated with a call to delete
as soon as the memory is no longer needed
▪ This is best done in the same function as the one that allocated the memory
▪ For dynamically-created objects, new should be used in the constructor and
delete should be used in the destructor
76
Thank You All
77
Acknowledgment: The slides are adapted from the 2012 Pearson Education, Inc.