Pointers
(CS 217)
Dr. Muhammad Aleem,
Department of Computer Science,
National University of Computer & Emerging Sciences,
Islamabad Campus
From C++ Code to Process
• C++ source files
– .cpp; .h
C++ source code
• Binary files compiling
– .o
binary files
linking
• Executable (linux, Ubuntu, …)
– [Link] executable
running
• Process process
– Managed by OS
C++ Memory Models
• C++ leaves memory management mostly up to the
programmer:
ve++: write programs that use memory very
efficiently
Ve--: write programs that waste memory or do not
work at all
• For efficient program working, we need good
understanding of the memory models
C++ Memory Models
• Common errors caused by poor memory
management:
– Using a variable before it has been initialized
– Allocating memory for storage and not deleting it
– Using a value after it has been deleted
• What are the solutions?
– ….
Main Memory
Network Audio
Data Bus
CPU
Disk Video
Memory
shared by all processes
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 constant
– 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 0
– support function call/return and text
recursive functions data
bss
– grow to low address
heap
stack
0xffffffff
Summary: Process Address Space
• text: program text/code
0
text
• data: initialized globals & static data data
bss
• bss: un-initialized globals & 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
311 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, that stores an address.
Introduction to Pointers
• We can declare pointers as follows:
Type* <variable Name>;
– Example:
int* P;
- 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;
Example
char *string = “hello”;
0
text
const int iSize=8;
data
char* f(int x)
{ bss
char *p;
heap
p = new char[iSize];
return p;
}
stack
0xffffffff
Example
char *string = “hello”;
0
const int iSize=8; text
data
char* f(int x)
{ bss
char *p;
heap
p = new char[iSize];
return p;
}
stack
0xffffffff
Variable Lifetime
• text:
– program startup
– program finish
0
• data, bss: text
– program startup
data
– program finish
bss
• heap:
– dynamically allocated heap
– de-allocated (free)
• stack:
– function call
– function return stack
0xffffffff
Example
char *string = “hello”;
program 0
startup text
const int iSize=8;
data
char *f (int x)
{ bss
char *p; when f() is
called heap
p = new char[iSize];
return p;
}
live after allocation; till
delete or program finish stack
0xffffffff
Variable 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
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.
Differences between Static and 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
• 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:
Example
int main()
{
int *p;
p = new int; 0
*p = 99; text
data
return 0;
} bss
heap
0xffffffff stack
Example
int main()
{
int *p;
p = new int; 0
*p = 99; text
data
return 0;
} bss
heap
#@%*&
0xffffffff stack
Example
int main()
{
int *p;
p = new int; 0
*p = 99; text
data
return 0;
} bss
heap
99
0xffffffff stack
Aliasing
int main()
{
int *p, *q;
0
p = new int; text
*p = 99;
data
q = p;
bss
return 0;
heap
}
99
q
p
0xffffffff stack
Aliasing
int main()
{
int *p, *q;
0
p = new int; text
*p = 99;
q = p; data
bss
*q = 88;
heap
return 0;
} 88
q
p
0xffffffff stack
Aliasing
int main()
{
int *p, *q;
p = new int; 0
*p = 99; text
q = p; data
*q = 88; bss
delete q; heap
return 0; $%#^&
}
q
p
0xffffffff stack
Dangling Pointers
int main()
{
int *p, *q;
p = new int; 0
*p = 99; text
q = p;
P and q are dangling pointers data
*q = 88; WHY?
bss
delete q;
heap
*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:
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?
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.)
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
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 (Cont.)
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
Array name is the starting address of the array
• Let int A[25];
int *p; int i, j;
• Let p = A;
• Then p points to A[0]
p + i points to A[i]
&A[j] == p+j
*(p+j) is the same as A[j]
Arrays and Pointers
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’;
So, What
int* p1; 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 Using Pointers
• We know, Array name denotes the memory address of
its first slot. Address Data
– Example: 980 Element 0
int List [ 50 ]; 982 Element 1
int *Pointer; 984 Element 2
Pointer = List; 986 Element 3
• Other slots of the Array (List [50]) can be accessed 988 Element 4
using by performing Arithmetic operations on Pointer. 990 Element 5
• For example the address of (element 4th) can be 992 Element 6
accessed using:- 994 Element 7
int *Value = Pointer + 3; 996 Element 8
• The value of (element 4th) can be accessed using:-
int Value = *(Pointer + 3);
…
…
998 Element 49
Accessing 1-Demensional Array
Address Data
…. 980 Element 0
…. 982 Element 1
int List [ 50 ]; 984 Element 2
int *Pointer; 986 Element 3
293
Pointer = List; // Address of first Element 988 Element 4
990 Element 5
int *ptr; 992 Element 6
ptr = Pointer + 3; // Address of 4th Element 994 Element 7
*ptr = 293; // 293 value store at 4th element 996 Element 8
address
…
} …
998 Element 49
Accessing 1-Demensional Array
We can access all element of List [50] using Pointers
and for loop combinations. Address Data
980 Element 0
… 982 Element 1
… 984 Element 2
int List [ 50 ]; 986 Element 3
int *Pointer; 988 Element 4
Pointer = List; 990 Element 5
for ( int i = 0; i < 50; i++ ) 992 Element 6
{ 994 Element 7
cout << *Pointer; 996 Element 8
Pointer++; // Address of next element …
}
…
998 Element 49
This is Equivalent to
for ( int loop = 0; loop < 50; loop++ )
cout << Array [ loop ] ;
Accessing 2-Demensional Array
• Note that the statements
int *Pointer; Address Data
Pointer = &List [3]; 980 Element 0
• represents that we are accessing the address 982 Element 1
of 4th slot. 984 Element 2
986 Element 3
• In 2-Demensional array the statements 988 Element 4
990 Element 5
int List[ 5 ][ 6 ];
992 Element 6
int *Pointer;
994 Element 7
Pointer = &List [3];
996 Element 8
…
Represents that we are accessing the address
of 4th row …
998 Element 50
• or the address the 4th row and 1st column.
Accessing 2-Demensional Array
– int List [ 9 ] [ 6 ]; Column
– int *ptr; 0 1 2 3 4 5
– ptr = &List [3]; 0 300 302 304 306 308 310
1 312 314 316 318 320 322
2 324 326 328 330 332 334
• To access the address of 4th row 2nd 3 336 338 340 342 344 346
Row
4 348 350 352 354 356 358
column: 5 360 362 364 366 368 370
– ptr++; // address of 4th row 2nd 6 372 374 376 378 380 382
7 384 386 388 390 392 394
column 8 396 398 400 402 404 406
– (faster than normal array accessing
Why?)
– Equivalent to List [3][1] ; Memory address
Accessing 2-Demensional Array
• We know computer can perform only
one operation at any time (remember Column
fetch-decode-execute cycle). 0 1 2 3 4 5
0 300 302 304 306 308 310
• Thus to access List [3][1] element 1 312 314 316 318 320 322
(without pointer) two operations are 2 324 326 328 330 332 334
involved:- 3 336 338 340 342 344 346
Row
– First to determine row List [3] 4 348 350 352 354 356 358
– Second to determine column List[3][1] 5 360 362 364 366 368 370
6 372 374 376 378 380 382
7 384 386 388 390 392 394
• But using pointer we can reach the 8 396 398 400 402 404 406
element of 4th row 2nd column (directly)
by increment our pointer value (which is
a single operation).
– ptr+1; // 4th row 2nd column Memory address
– ptr+2; // 4th row 3rd column
– ptr+3; // 4th row 4th column
Differences between Static and 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
• Declarations are used to statically allocate memory,
– the new operator is used to dynamically allocate
memory
Returning Memory to the Heap
• How Big is the Heap?
– Most applications request memory from the heap when
they are running;
– It is possible to run out of memory (you may even have
gotten a message like "Running Low On Virtual
Memory")
– So, it is important to return memory to the heap when
you no longer need it
Casting pointers
Pointers have types, so you cannot just do
int *pi; double *pd;
pd = pi;
Even though they are both just integers, C++ not
allows (Error)
Casting pointers
C++ will let you change the type of a pointer
with an explicit cast
int *pi; double *pd;
pd = (double*) pi;
Note: Values differenced after cast are
undermined (difference of 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.
Dynamic 2D Arrays
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
Dynamic two
dimensional arrays
Can we vary size of each
column in Dynamic 2D Array
(using double pointer)
PP start of array of pointers
*PP First Address pointed by first row (sub array)
*(*PP) First value of first array
(*PP)++ Move to next address in the first array
PP++ Move to Next row (second array address
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* const ptrInt=&v1; //ptr is constant pointer to int
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*
*ptr = 6; // change value to 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;
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
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;
}
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;
}
Questions (last lecture)
c
Address of character variable…