0% found this document useful (0 votes)
80 views

CS 217 2 Pointers

The document discusses C++ memory models and pointers. It explains how C++ code is compiled into binary files and then executed as a process. It describes the different memory sections of a process including text, data, bss, heap and stack. It introduces pointers and how they store memory addresses. It also covers dereferencing pointers, pointer assignment, and variable lifetimes based on memory section. Finally, it contrasts static and dynamic memory allocation.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
80 views

CS 217 2 Pointers

The document discusses C++ memory models and pointers. It explains how C++ code is compiled into binary files and then executed as a process. It describes the different memory sections of a process including text, data, bss, heap and stack. It introduces pointers and how they store memory addresses. It also covers dereferencing pointers, pointer assignment, and variable lifetimes based on memory section. Finally, it contrasts static and dynamic memory allocation.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 81

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, …)
– a.out 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…

You might also like