Pointers
Dr. Muhammad Aleem,
Department of Computer Science,
National University of Computer & Emerging Sciences,
Islamabad Campus
Main Memory
Network Audio
Data Bus
CPU
Disk Video
Memory
shared by all processes
What is a process?
An executing program (loaded in memory) is called process…
Virtual Memory
(How a CPU see’s a Process?)
• Continuous memory space
for all process: 0
– Set of locations as needed by
a process
0xffffffff
Organization of Virtual Memory: .text
• Program code and constants
– binary form 0
text
– loaded libraries
– code instructions
– space calculated at compile-
time
0xffffffff
Organization of Virtual Memory: .data
• Data: initialized global data in
the program 0
text
– Ex: int size = 100;
data
bss
• BSS: un-initialized global data in
the program
– Ex: int length;
0xffffffff
Organization of Virtual Memory: heap
• Heap: dynamically-allocated spaces
– Ex: new, delete
0
– dynamically grows as program runs text
data
bss
heap
0xffffffff
Organization of Virtual Memory: stack
• Stack: local variables in functions
– support function call/return and 0
recursive functions text
– grow to low address data
bss
heap
0xffffffff stack
Summary: Process Address Space
• text: program text/code and constants
0
text
• data: initialized global & static data data
bss
• bss: un-initialized global & static data heap
• heap: dynamically managed memory
stack
0xffffffff
• stack: function’s local variables
Introduction to Pointers
• When we declare a variable, some memory is
allocated for it.
• Thus, we have two properties for any variable:
1. Its Address
2. and its Data value
Memory Address Value
E.g., char ch = ‘A’;
ch
1011 65
Introduction to Pointers
• How to get the memory-address of a variable?
• Address of a variable can be accessed through the
referencing operator “&”
– Example: &i will return memory location
where the data value for “i” is stored.
A pointer is a variable
Pointer stores only address
Creating a Pointer Variable
Type* <variable Name>;
Example:
int* P;
float* P2;
- creates a pointer variable named “P”, that will
store address (memory location) of some int type
variable.
The address of Operator &
• The & operator can be used to determine the
address of a variable, which can be assigned to a
pointer variable
Examples:
Dereferencing Operator *
• C++ uses the * operator in yet another way with
pointers
– "The variable values pointed to by p" *p
– Here the * is the dereferencing operator
p is said to be dereferenced
int v1=99;
int* p= &v1;
cout<<“ P points to the value: “<<*p;
Dereferencing Pointer Example
int v1 = 0;
v1 and *p1 now refer to
int* p1 = &v1; the same variable
*p1 = 42;
cout << v1 << endl;
cout << *p1 << endl;
Output:
42
42
Pointer Assignment and Dereferencing
• Assignment operator ( = ) is used to assign value
of one pointer to another
• Pointer stores addresses so p1=p2 copies an
address value into another pointer
int v1 = 55; Output:
int* p1 = &v1;
int* p2; 55
p2=p1; 55
cout << *p1 << endl;
cout << *p2 << endl;
Storage and Data Allocation of C++ Program
char *str = “hello”;
0
const int iSize=8; text
data
char* f(int x)
{ bss
char *p;
heap
p = new char[iSize];
return p;
}
stack
0xffffffff
Variables’ Lifetime
• text:
– program startup
– program finish
0
text
• data, bss:
– program startup data
– program finish bss
heap
• heap:
– dynamically allocated
– de-allocated (free)
• stack: 0xffffffff
stack
– function call
– function return
Example
char *string = “hello”; 0
program text
startup
const int iSize=8; data
char *f (int x) bss
{
char *p; when f() is heap
called
p = new char[iSize];
return p;
}
Live after allocation; till 0xffffffff stack
delete or program finish
Variables’ Initialization
• text:
– Read-only (once; e.g., constants)
0
text
• data
data
– on program startup
bss
• bss:
heap
– un-initialized (though some systems initialize with 0)
• heap:
– un-initialized
stack
0xffffffff
• stack:
– un-initialized
Pointer Assignments (Aliasing)
• Some care is required making assignments to
pointer variables:
p1 = p2; // changes the location that p1 "points" to
*p1 = *p2; // changes the value at location that
// p1 "points" to
Another Pointer Example
int i = 1;
int j = 2;
int* ptr;
ptr = &i; // ptr points to location of i
*ptr = 3; // contents of i are updated
ptr = &j; // ptr points to location of j
*ptr = 4; // contents of j are updated
cout << i << " " << j << endl;
Output:
3 4
Swapping variables using Pointers
void main() {
char a = ‘A';
char b = ‘Z';
char *Ptr1= &a;
char *Ptr2= &b;
char temp = *Ptr1;
*Ptr1 = *Ptr2;
*Ptr2 = temp;
cout << a << b << endl;
}
Dynamic Memory Allocation
• Used when space requirements are unknown at compile
time
• Most of the time the amount of space required is
unknown at compile time
• Dynamic Memory Allocation (DMA):-
– With Dynamic memory allocation we can
allocate/deletes memory (elements of an array) at
runtime or execution time.
Static VS. Dynamic Memory Allocation
• Dynamically allocated memory is kept on the memory
heap (also known as the free store)
• Dynamically allocated memory cannot have a "name", it
must be referred to (using address)
• Declarations are used to statically allocate memory
• The new operator is used to dynamically allocate memory
Dynamic Memory Allocation
Heap management in C++ is explicit:
Dynamic Allocation - Example
int main()
{
int *p;
0
p = new int; text
*p = 99;
data
return 0; bss
}
heap
0xffffffff stack
Dynamic Allocation - Example
int main()
{
int *p;
0
p = new int; text
*p = 99;
data
return 0; bss
}
heap
#@%*&
0xffffffff stack
Dynamic Allocation - Example
int main()
{
int *p;
0
p = new int; text
*p = 99;
data
return 0; bss
}
heap
99
0xffffffff stack
Pointer Aliasing
int main()
{
int *p, *q;
0
p = new int; text
*p = 99; data
q = p;
bss
return 0; heap
}
99
q
Pointer Aliasing: same memory p
location can be accessed using
different names. 0xffffffff stack
Pointer Aliasing
int main()
{
int *p, *q;
0
p = new int; text
*p = 99; data
q = p; bss
*q = 88; heap
88
return 0;
}
q
p
0xffffffff stack
Pointer Aliasing
int main()
{
int *p, *q;
0
p = new int; text
*p = 99;
q = p; data
bss
*q = 88;
heap
delete q;
$%#^&
return 0;
}
q
p
0xffffffff stack
Dangling Pointers
int main()
{
int *p, *q;
p = new int; 0
*p = 99; text
q = p; data
*q = 88; P and q are dangling bss
pointers, WHY? heap
delete q;
*p = 77; $%#^&
return 0;
} q
p
0xffffffff stack
Dangling Pointers
• The delete operator does not delete the pointer, it
takes the memory being pointed to and returns it to
the heap
• It does not even change the contents of the pointer
• Since the memory being pointed to is no longer
available (and may even be given to another
application), such a pointer is said to be dangling
Avoiding a Dangling Pointer
• For Variables:
delete v1;
v1 = NULL;
• For Arrays:
delete[ ] arr;
arr = NULL;
Returning Memory to the Heap
• Remember:
– Return memory to the heap before undangling the
pointer
• What's wrong with the following code:
ptr = NULL;
delete ptr;
Memory Leaking
int main()
{
int *p;
p = new int;
// make the above space unreachable; How?
p = new int;
// even worse…; WHY?
while (1)
p = new int;
return 0;
}
Memory Leaking
void f ( )
{
int *p;
p = new int;
return;
}
int main ( )
{
f ( );
return 0;
}
Memory Leaks
• Memory leaks when it is allocated from the heap
using the new operator but not returned to the
heap using the delete operator
Memory Leaking and Dangling Pointers
• Dangling pointers and memory leaking are evil
sources of bugs:
– hard to debug
• may appear after a long time of run
• may far from the bug point
– hard to prevent
What should be the good programming practices while
using Pointers?
Null Address
• Like a local variable, a pointer is assigned a random
value (i.e., address) if not initialized
• 0 is a pointer constant that represents the empty or
Null address
• Should be used to avoid dangling pointers
– Cannot Dereference a Pointer whose value is Null:
int *ptr = 0; OR int *ptr=NULL;
cout<< *ptr << endl; // ERROR: ptr
// does not point to
// a valid address
Pointers Data-Type
• Question:
Why is it important to declare the type of the variable
that a pointer points to?
Aren’t all memory addresses of the same length?
Pointers Type
• Answer:
- All memory addresses are of the same length,
– However, with operation “p++” where “p” is a
pointer the compiler needs to know the data
type of the variable “p” (to jump at next memory
location)
Examples:
–If “p” is a character-pointer then “p++” will
increment “p” by one byte (next location)
–if “p” is an integer-pointer its value on “p++”
would be incremented by 4 bytes (next loc.)
Relationship Between Pointers and Arrays
• Arrays and pointers are closely related
– Array name is like constant pointer
– All arrays elements are placed in the consecutive
locations.
• Example:- int List [10]; List is the start address of
array
– Pointers can do array subscripting operations
We can access array elements using pointers.
• Example:- int value = List [2]; //value assignment
int* p = List; //address assignment
Relationship Between Pointers and Arrays
Effect:-
- List is an address, no need for &
- The bPtr pointer will contain the address of the first
element of array List.
– Element List[2] can be accessed by *(bPtr+2)
Relationship between Arrays and Pointers
• Arrays and pointers are closely related:
void main()
{
int numbers[]={10,20,30,40,50};
cout<<numbers[0]<<endl; 10
cout<<numbers<<endl; Address e.g., &34234
cout<<*numbers<<endl; 10
cout<<*(numbers+1); 20
}
Arrays and Pointers
Warning: These byte increments are based on 32-bit architecture,
adjust according to the machine architecture.
Pointer Arithmetic
Only two types of arithmetic operations allowed:
1) Addition : only integers can be added
2) Subtraction: only integers be subtracted
Which of the following are valid/invalid?
Comparing Pointers
• If one address comes before another address in
memory, the first address is considered less than the
second address.
• Two pointer variables can be compared using C++
relational operators: <, >, <=, >=, ==
• In an array, elements are stored in consecutive
memory locations, E.g., address of Arr[2] will be
smaller than the address of Arr[3] etc.
Void Pointer
• void* is a pointer to no type at all:
• Any pointer type may be assigned to void *
int iVar=5;
float fVar=4.3;
This is a great advantage…
char cVar=‘Z’;
int*
So, p1;
What are the limitations/challenges?
void* vp2;
p1 = &iVar; // Allowed
p1 = &fvar; // Not Allowed
P1 = &cVar; // Not Allowed
vp2 = &fvar; // Allowed
vp2 = &cVar; // Allowed
vp2 = &iVar; // Allowed
Accessing 1-Demensional Array
Address Data
…. 980 Element 0
…. 984 Element 1
int List [50]; 988 Element 2
int *p; 992 293
p = List; 996 Element 4
p = p + 3; 1000 Element 5
*P = 293; 1004 Element 6
1008 Element 7
} 1012 Element 8
…
…
1180 Element 49
Accessing 1-Demensional Array
… Address Data
…
980 Element 0
int List [ 50 ];
984 Element 1
int *Pointer;
988 Element 2
Pointer = List;
992 293
for ( int i = 0; i < 50; i++ )
996 Element 4
{
1000 Element 5
cout << *Pointer;
1004 Element 6
Pointer++; //Address of next element
1008 Element 7
1012 Element 8
}
…
…
This is Equivalent to
1180 Element 49
for (int loop = 0; loop<50; loop++)
cout<<Array[loop];
Accessing 2-Demensional Array
• In 1D array if we use: Addres Data
int *Pointer; s
980 Element 0
Pointer = &List[3]; //accessing the 984 Element 1
// address of 4th slot. 988 Element 2
992 293
996 Element 4
• In 2-Demensional array: 1000 Element 5
1004 Element 6
int main()
1008 Element 7
{
1012 Element 8
int A[3][3]={{1,2,3},{4,5,6},{7,8,9}};
int *p; …
p=A[2];
…
cout<<"\nvalue of p= "<<*p<<endl; //outputs 7
return 0; 1180 Element 49
}
Demo Code:
pointersArrays1.cpp
Accessing 2-Demensional Array
Full array traversal of 2D array:
int main()
{
int A[3][3]={{1,2,3},{4,5,6},{7,8,9}};
int *p;
p=A;
for(int i=0;i<9;i++)
{
cout<<"\nValue of p= "<<*p<<endl;
p++; // or just cout<<*(p+i)
}
return 0;
}
• Pointer access is faster as compared to 2D array notation (one
address calculation as compared to [ ][ ] row and col addresses)
Casting pointers
Pointers have types, so you cannot do
int *pi; double *pd;
pd = pi;
C++ will let you change the type of a pointer with an
explicit cast:
int *pi; double *pd;
pd = (double*) pi;
Warning: Values dereferenced after the cast are undermined (because of
possibly difference in memory size)
Creating Dynamic 2D Arrays
Two basic methods:
1. Using a single Pointer
2. Using a Array of Pointers
Dynamic two dimensional arrays
1. Using a single Pointer
• Total elements in a 2D Array:
– m * n (i.e., rows * cols)
5 rows * 4 columns
= 20 elements
Target Approach=
• allocate 20 elements using dynamic allocation
• Use a single pointer to point and access those items.
#include<iostream>
#include <stdlib.h> Dynamic 2D Arrays
#include<time.h>
using namespace std;
int main()
{
int M=4; int N=5;
int* Arr=new int[M*N];
srand(time(0));
//set values
for(int i=0;i<M;i++)
for(int j=0;j<N;j++)
*(Arr + i*M+j) = rand()%100;
//display values
for(int i=0;i<M;i++) {
for(int j=0;j<N;j++) {
cout<<*(Arr + i*M+j)<<" ";
//cout<<(Arr+i*M)[j]<<" ";
}
cout<<endl;
} Demo Code:
delete[] Arr; pointersArrays2.cpp
return 0; }
Dynamic 2D Array – Double Pointer
2. Using a Pointer that points to Array of Pointer
• Total elements in a 2D Array: M_rows * N_coulmns
Ptr2D
(Pointer to a Pointer)
Dynamic 2D Array – Double Pointer
int main() {
int M=4; int N=6;
Dynamic 2D Arrays
int** A=new int*[M]; srand(time(0)); Demo Code:
pointersArrays3.cpp
for(int i=0;i<M;i++) /*Allocate subarrays */
A[i]=new int[N];
for(int i=0;i<M;i++)
for(int j=0;j<N;j++)
A[i][j] = rand()%100;
//display values
for(int i=0;i<M;i++) {
for(int j=0;j<N;j++) { A start of array of pointers
cout<<A[i][j]<<" "; *A First Address pointed by first row (sub-array)
}
*(*A) First value of first array
cout<<endl;
} (*A)++ Move to next address in the first array
A++ Move to Next row (second sub-array)
//deallocate memory
for(int i=0;i<M;i++)
delete[] A[i];
delete[] A; Can we vary size of each column in
return 0; Dynamic 2D Array (using double pointer)
}
Dynamic 2D Array
(Varying Row Size)
Home Work
- Manipulating a 3D Array
1. Using a single pointer
2. Using a triple pointer
Constant Pointer
• A constant pointer is a pointer that is constant, such
that we cannot change the location (address) to which
the pointer points to:
char c = 'c';
char d = 'd';
char* const ptr1 = &c;
ptr1 = &d; // Not Allowed
int v1=90;
int* const ptr2=&v1;
Pointer to Constant 1/2
• we cannot set a non-const pointer to a const data-item
const int value = 5; // value is const
int *ptr = &value; // compile error: cannot convert
// const int* to int*
// To avoid such operations *ptr = 6;
const int value = 5;
const int *ptr = &value; // this is okay,
*ptr = 6; // not allowed,
// we cannot change a const value
Pointer to Constant 2/2
• A pointer through which we cannot change the value
of variable it points is known as a pointer to constant.
• These type of pointers can change the address they
point to but cannot change the value kept at those
address.
int var1 = 0;
const int* ptr = &var1;
*ptr = 1; // Not Allowed
cout<<*ptr;
Home-Work: char* and const
• const char *ptr : This is a pointer to a constant
character. You cannot change the value pointed by ptr, but
you can change the pointer itself.
• char* const ptr : This is a constant pointer to non-
constant character. You cannot change the pointer p, but
can change the value pointed by ptr.
• const char* const ptr : This is a constant pointer to
constant character. You can neither change the value
pointed by ptr nor the pointer ptr.
C-String and Char Pointer
• A String: is simply defined as an array of characters
char* s;
// s is the address of the first character (byte) of the string
• A valid C string ends with the null character ‘\0’
• Direct initialization char* <string Literal>;
char* s=“FAST”;
cout<<s<<sizeof(s);
cout<<++s<<sizeof(s);
char [ ] VS. char *
char A[20]=“FAST”; char* P=“FAST”;
1) A is an Array 1) P is a pointer variable
2) A++; //invalid 2) P++; //Valid
3) sizeof(A) 20 Characters or bytes 3) Sizeof(P) 4 Characters or bytes
4) A and &A points to same memory 4) P points to start address where
address characters are stored, and &P points to
address of pointer variable.
5) A=“PAKISTAN”; //invalid
A is an address, “PAKISTAN” is the start 5) P=“PAKISTAN” //valid
address where “PAKISTAN” string is stored
in memory.
6) A[0]=‘p’; //Valid 6) P[0]=‘p’; //inValid
7) A is stored in stack 7) P is stored in Stack, “FAST” is stored in
“Text” section (Read-only)
C-String and Char Pointer - Example
// Copying string using Pointers
char* str1 = “Self-conquest is the greatest victory.”;
char str2[80]; //empty string
char* src = str1;
char* dest = str2;
while( *src ) //until null character,
*dest++ = *src++; //copy chars from src to dest
*dest = ‘\0’; //terminate dest
cout << str2 << endl; //display str2
Functions Pass by using Reference Pointer
c
• Pass-by-reference with pointer arguments
• Use pointers as formal parameters and
addresses as actual parameters
• Pass address of argument using & operator
– Arrays not passed with & because array name
already an address
– Pointers variable are used inside function
Pass by Reference Pointers– Example1
c
void func(int *num)
{
cout<<"num = "<<*num<<endl;
*num = 10;
cout<<"num = "<<*num<<endl;
}
void main()
{
int n = 5;
cout<<"Before call: n = "<<n<<endl;
func(&n);
cout<<"After call: n = "<<n<<endl;
}
Pass by Reference Pointers– Example2
c
void compDouble(int* Ar)
{
for(int i=0;i<10;i++)
{ *Ar=(*Ar)*2;
Ar++;
}
}
void main()
{ int Arr[10]={0,1,2,3,4,5,6,7,8,9};
compDouble(Arr);
for(int i=0;i<10;i++)
cout<<Arr[i]<<endl;
}
Any Questions!