1. Pointers
Course Code: CSC1102 &1103
Dept. of Computer Science
Faculty of Science and Technology
Course Title: Introduction to Programming
Lecturer No: 9.1 Week No: 9 Semester: Spring 2024-2025
Course
Instructor:
Mashiour Rahman, Associate Professor,
mashiour@aiub.edu
2. Outline
Pointers
Pointers and Addresses
Pointer Types – NULL, void, const
Pointers and Arrays
Pointer Arithmetic
Dynamic Memory Allocation – new and delete
3. int x;
An Integer value held within the
location &x denoted by x
A location of size int denoted by
&x
Main Memory
4 bytes (int x)
x
&
x
int
*z;
An Address value denoted by z
holding a location of an int value
A location of size 4 bytes (?)
denoted by &z Main Memory
4 bytes (?) for
storing memory address
z
&
z
&x
• The operator * here is known as Indirection/Dereference operator.
• (?) The size of a pointer in C depends on the architecture (bit system) of the machine, not the
data type it points to. On a 32-bit and a 64-bit system, all pointers typically occupy 4 and 8
bytes respectively.
The Integer Value at location z
denoted by *z
4 bytes (int x)
x
*z==
x
int x;
int
*z=&x;
int *z,
x;
z = &x;
or
4. Declaring a Pointer variable
int count = 10;
int *p;
p = &count;
&count gives the location/memory address of the variable count.
Pointer variable p stores the location/memory address of the integer variable count after
the execution of p = &count;
We say that p "points to" count.
int *p; // p points to a location that contains an integer
char *q; // q points to a location that contains a character
float *r; // r points to a location that contains a float
Data_Type * Pointer_Variable_name
Data type of the element that is
stored and/or pointed to by the
address value of this variable
Indirection/Dereference
operator
Variable name
as per the
identifier rule.
5. Example: pointers
// Program to illustrate pointers
#include <iostream>
Using namespace std;
int main (void){
int x = 10;
cout << "x = " << x << endl;
cout << "&x = " << &x << endl;
int *z;
cout << "&z = " << &z << endl;
z = &x;
cout << "z = " << z << endl;
cout << "*z = " << *z << endl;
*z = 4;
cout << "*z = " << *z << endl;
cout << "x = " << x << endl;
x = 6;
cout << "x = " << x << endl;
cout << "*z = " << *z << endl;
return 0;
}
OUTPUT:
x = 10
&x = 0x61febc
&z = 0x61feb8
z = 0x61febc
*z = 10
*z = 4
x = 4
x = 6
*z = 6
Main Memory
z
&z=
0x61feb8
&x= 0x61febc
4 bytes (int x)
x= 10
4 bytes (location)
z= 0x61febc *z= x= 10
*z= x= 4
*z= x= 6
6. Setting pointer variables
int *p;
*p = 4;
Severe runtime error !!! the value 4 is stored in the location to
which p points. But p, being uninitialized, has a random value,
so we cannot know where the 4 will be stored !
int *p;
int x;
p = &x;
*p = 4;
int *p;
int *p1;
int x;
p1 = &x;
p = p1;
*p = 4;
The value of a pointer in C is meaningless until it is set pointing to something !
How to set pointer values: Using the address operator
Using directly assignments between pointer variables
7. Pointers: Types
There are several special types of pointers that used or referred to in different
contexts.
NULL Pointer: The NULL Pointers do not point to any memory location. It
represents the absence of any address. A pointer variable of any type can be
assigned the NULL (keyword) value. This allows us to check whether the pointer
is pointing to any valid memory location.
Example:
int *ptr = NULL, a;
if(ptr == NULL) ptr = &a; //if(!ptr) ptr = &a;
Generic (void) Pointer: The generic pointers are of type void. They do not
have any associated data type. They can point to any data type. May be used
with explicit type cast to any type.
Example:
void *ptr;
int a;
ptr = &a;
8. Pointers: Types
Constant Variables:
The constant variable must be initialized at the time of the declaration.
The value of a constant variable cannot be re-assigned/changed anywhere in the
program.
Examples:
// const variables
char a;
const char b = 'M';
// value fixed
b = 'X'; // !!! INVALID !!!
// pointers
char c = 'M', d = 'R';
char *cP1 = &c;
*cP1 = 'X';
cP1 = &d;
*cP1 = 'X';
// const pointers – 3 ways
char c = 'M', d = 'R';
// 1. location fixed, value can
change
char * const cP2 = &c;
*cP2 = 'X'; //valid
cP2 = &d; // !!!invalid!!!
// 2. value fixed, location can
change
const char *cP2 = &c;
cP2 = &d; //valid
*cP2 = 'X'; // !!!invalid!!!
// 3. both value & location fixed
const char * const cP3 = &c;
9. Main Memory
4 bytes (int)
a
int a[3];
One location denoted
by a
Three value denoted by
a[0], a[1], a[2]
Here,
• a represents the starting location of array.
• a[0], a[1], a[2] are integer variables.
• &a[0], &a[1], &a[2] are their respective
locations.
• We can also denote a = &a[0].
• In int a[3]; the array name a is a constant (const) pointer.
• A constant pointer is a pointer whose address value cannot be changed.
• A pointer variable int *p can be assigned with the array name a which will assign the
starting location of the array to p.
int a[3] = {1, 2, 3};
int *p = a; // int *p = &a[0];
p
&p
&a[0] &a[2]
&a[1]
a[0] a[1] a[2]
Pointers and Arrays
10. Main Memory
4 bytes (int)
a
p
&p
&a[0] &a[2]
&a[1]
a[0] a[1] a[2]
• In int a[3]; the array name a is a
constant (const) pointer.
• A constant pointer is a pointer whose address
value cannot be changed.
• A pointer variable int *p can be assigned
with the array name a which will assign the
starting location of the array to p.
int a[3] = {1, 2, 3};
int *p = a; // int *p =
&a[0];
• For any data_type *p; declaration, p+i equivalent to p+
(i*sizeof(data_type)). For int *p; declaration, p+i equivalent to p+(i*4).
• So, if p points to any element of an array, p+i points to the next ith
element from p.
• If p points to start of array a, then by definition p points to the first element, a[0], p+1
points to the next element, a[1]. So, p+i points to the next ith
element, a[i].
• So, if *p is any element of an array, *(p+i) is the next ith
element from p.
• If *p is the start element of array a, then by definition *p is the element, a[0], *(p+1) is
the next element, a[1]. So, *(p+i) is the next ith
element, a[i].
a[0]==*p
a[1]==*(p+1
)
a[2]==*(p+2
)
&a[0]==p &a[2]==p+2
&a[1]==p+1
Pointers and Arrays – Arithmetic
11. • For any data_type *p;
declaration, p+i equivalent to p+(i*sizeof(data_type)).
• For int *p; declaration, p+i equivalent to p+(i*4).
• Increment/decrement (++ or --) pointer
p++ or p-- pointer
• Add/subtract ( + or += , - or -=) an integer to/from a pointer
p ± integer p ± integer * sizeof(type) pointer
• Pointers may be subtracted from each other
p1 - p2 integer [= # of bytes]
p1 - p2 integer / sizeof(type) integer [= # of
elements]
• Pointer arithmetic generally performed on pointer to array
Pointers Arithmetic
Main Memory
4 bytes (int)
a
P1=300
0
&p1
&a[0]=3000
&a[2]=3008
&a[1]=3004
a[0]==*p
a[1]==*(p+1
)
a[2]==*(p+2
)
int a[3], *p1, *p2, n;
p1 = a; // p1 = 3000
p1 += 2;
//p1 + (2*sizeof(int))= 3000+(2*4)=
3008
p2 = a; // p2 = 3000
n = p1 – p2; // n = 2
// 3008 – 3000 = 8/sizeof(int) = 8/4
= 2
/* from a[0] up to a[2] there are 2
P2
&p2
P1=300
8
P2=300
0
n
n=2
12. int main(void){
float M[5] = {22.5,34.8,46.8,59.1,68.3}, *p;
int i;
for(i=0; i<3; i++)
cout<<"M["<< i <<"] @"<< &M[i] <<": "<< M[i]
<<endl;
for(i=0, p=M; i<3; i++, p++){
(*p)++; //increases the value at location p
cout << "nM[" << i << "] @" << p << ": " <<
*p;
}
p = M;
cout << "nValue of M[0]:n";
cout << "M[0]t:t" << M[0] << endl;
cout << "*Mt:t" << *M << endl;
cout << "p[0]t:t" << p[0] << endl;
cout << "*pt:t" << *p << endl;
cout << "nValue of M[3]:n";
cout << "M[3]t:t" << M[3] << endl;
cout << "*(M+3)t:t" << *(M+3) << endl;
cout << "p[3]t:t" << p[3] << endl;
cout << "*(p+3)t:t" << *(p+3) << endl;
OUTPUT:
M[0] @0x61fe9c:
22.5
M[1] @0x61fea0:
34.8
M[2] @0x61fea4:
46.8
M[0] @0x61fe9c:
23.5
M[1] @0x61fea0:
35.8
M[2] @0x61fea4:
47.8
Value of M[0]:
M[0] :
23.5
*M :
23.5
p[0] :
23.5
Pointers and Arrays
Not possible with M as it is constant pointer
13. suit[0]
suit[1]
suit[2]
suit[3]
• Arrays can contain pointers
• Commonly used to store array of strings –
char *suit[ 4 ] = {"Hearts", "Diamonds", "Clubs", "Spades" };
• 5000 – 9000 in green fonts are locations.
• Each element of suit points to a char * (a string) at any other independent location.
• Array suit does not store strings, only points to strings.
• Array suit has fixed size, but each string can be of any sizes.
• Following code will print all the strings –
for(int i=0; i<4; i++)
cout << suit[i] << endl;
Array of Pointers
'H' 'e' 'a' 'r' 't' 's' '
0'
'D' 'i' 'a' 'm' 'o' 'n' 'd' 's' '
0'
'C' 'l' 'u' 'b' 's' '
0'
'S' 'p' 'a' 'd' 'e' 's' '
0'
suit[0]=6000
suit[1]=7000
suit[2]=8000
suit[3]=9000
OUTPUT:
Hearts
Diamonds
Clubs
Spades
suit=5000
5004
5008
5012
14. n1=6000
n2=7000
n3=8000
n4=9000
• For other data types (here int as example) –
int *num[4], n1[7]={1,2,3,4,5,6,7},
n2[9]={1,2,3,4,5,6,7,8,9},
n3[6]={1,2,3,4,5,6}, n4[7]={1,2,3,4,5,6,7};
// 5000 – 9000 in green fonts are locations.
num[0] = n1; num[1] = n2; num[2] = n3; num[3] = n4;
// can be accessed as 2-D array with varying sizes of array
int ArraySize[4] = {7, 9, 6, 7}; //size of n1, n2, n3, n4
// Other ways to calculate size are possible (like using
sizeof())
for(int i=0; i<4; i++){
cout << "num[" << i << "] = n" << i+1 << " : ";
for(int j=0; j<ArraySize[i]; j++)
cout << num[i][j] << " "; // *(num[i]+j) or
*(*(num+i)+j))
cout << endl;
}
num[0]
num[1]
num[2]
num[3]
Array of Pointers
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6
1 2 3 4 5 6 7
num[0]=n1=6000
num[1]=n2=7000
num[2]=n3=8000
num[3]=n4=9000
OUTPUT:
num[0] = n1 : 1 2 3 4 5 6 7
num[1] = n2 : 1 2 3 4 5 6 7 8 9
num[2] = n3 : 1 2 3 4 5 6
num[3] = n4 : 1 2 3 4 5 6 7
num=5000
5004
5008
5012
15. Dynamic Memory Allocation
• The exact size of an array is unknown until the compile time, i.e., time when a compiler
compiles code into an executable form. The size of array declared initially can be
sometimes insufficient and sometimes more than required.
• What if we need a variable amount of memory that can only be determined during
runtime?
• We may require multiple variable for a task, which may no longer required in the later
part of the program. These variables are taking space until the end of the program
needlessly, as memory is automatically allocated during declaration and deallocated
when the program finishes execution.
• Dynamic memory allocation allows a program to obtain more memory space, while
running or to release space when no space is required. This allows the programmer to
allocate memory manually when needed and deallocate when not required.
• C++ has two operators new and delete that perform the task of allocating and
deallocating/freeing the memory (respectively) using pointer variables. The allocation is
done at runtime.
• For dynamically allocated memory it is programmers’ responsibility to deallocate
memory when no longer needed. If programmer doesn’t deallocate memory, it causes
memory leak (memory is not deallocated until program terminates).
16. Operators – new and delete
• Operators new and new[]
In order to request/assign dynamic memory into a pointer variable, we use the
operator new followed by a data type specifier. For array, the data type specifier is
followed by the number of memory blocks required within brackets []. It returns a
pointer to the beginning of the newly allocated array. Syntax:
pointer_variable = new data_type; // for single element
pointer_variable = new data_type [total_elements]; // for
array
• Operators delete and delete[]
Since the necessity of dynamic memory is usually limited to specific moments within a
program, once it is no longer needed it should be freed/deallocated so that the
memory becomes available again for other requests of dynamic memory. This is the
purpose of the operator delete. Syntax:
delete pointer_variable; // for single variable
delete [] pointer_variable; // for array
In the case of a pointer_variable = NULL, delete produces no effect.
17. Dynamic Memory Allocation
OUTPUT:
# of elements:
5
Enter elements:
2
6
7
4
3
Main Memory
n
i
pt
r
2 6 7 4 3
su
m
5
0 1 2 3 4
0
1
2
3
4
2
8
15
19
22
0
// new, delete
int main(void){
int n, i, *ptr;
cout << "# of elements: ";
cin >> n; //input 5
ptr = new int[n];
if(ptr == NULL){ // unable to allocate
cout << "Error! memory not
allocated.";
return 0;
}
int *sum = new int;
cout << "Enter elements:n";
for(i=0, *sum=0; i<n; ++i){ //input 2 6 7
4 3
cin >> ptr[i]; // (ptr + i)
*sum += ptr[i]; // *(ptr + i)
}
cout << "Sum = " << *sum;
delete sum; //single memory deallocated
delete [] ptr; //array memory deallocated
*su
m
5
19. int **num, r, c;
cin >> r; // input 4
num = new int*[r]; // int *num[r];
for(int i=0; i<r; i++){
cin >> c; // input 4 2 5 3
num[i] = new int[c]; // int num[r][c];
}
// 6000 – 9000 in green fonts are locations.
for(int i=0; i<r; i++)
delete [] num[i]; //free memory of each row num[i]
delete num; //free memory of num
2-D Dynamic Array – different length of
row
*(num+0)=num[0]
*(num+1)=num[1]
*(num+2)=num[2]
*(num+3)=num[3]
num=7000
7004
7008
7012
1 2 3 4
6 7
2 3 4 5 6
7 8 9
*(num+0)=num[0]=800
0
*(num+1)=num[1]=801
6
*(num+2)=num[2]=802
4
*(num+3)=num[3]=804
4
num
&num=600
0
20. • Consider the statement int *p; which declares a pointer p, and like any other variable this space will
contain garbage (random numbers), because no statement like p = &someint; or p = new
int; has yet been encountered which would give it a value.
• Writing a statement int *p=2000; is syntactically correct as p will point to the 2000th
byte of the
memory. But it might fail as byte 2000 might be being used by some other program or may be being
used by some other data type variable of the same program. So, such initialization or assignment must
be avoided unless the address provided is guaranteed to be safe.
• There is an important difference between these definitions:
char amsg[] = "now is the time"; /* an array */
char *pmsg = "now is the time"; /* a pointer */
• amsg is an array, just big enough to hold the sequence of characters ending with '0' that initializes
it. Individual characters within the array may be changed but amsg will always refer to the same
storage.
• On the other hand, pmsg is a pointer, initialized to point to a string constant; the pointer may
subsequently be modified to point elsewhere, but the result is undefined if you try to modify the string
contents.
Pointers and Initialization