Vous êtes sur la page 1sur 138

Basic Memory Management and Pointers in C++

CS 1037a Topic 2

Overview:

part I

Pointers - a basic variable type


values of pointer variables (or pointers)
computer memory as a huge 1D array

basic operations with pointer variables Why pointers?


pointers to (static) objects/variables pointers as function arguments pointers and arrays pointers to dynamic objects/variables
2-2

Overview:

part II

Dynamic Memory Operations


dynamic vs. static objects
Why dynamic objects are needed? operators new and delete

dynamic vs. static arrays


operators new[ ] and delete[ ]

stack and heap memory

2-3

Overview:

part III

Examples of Dynamic Arrays


dynamic array of objects versus array of pointers to dynamic objects dynamic arrays of pointers double pointers dynamic 2D arrays objects containing dynamic arrays
2-4

Related materials
from Main and Savitch Data Structures & other objects using C++

Sec. 4.1: pointers and dynamic memory Sec. 4.2: pointers and arrays as parameters
from CS1037 labs

Lab 2, lab 3, and Lab 4


from ES1036 lecture notes

Topic 6 and Topic 9 (parts 1&2)


2-5

Part I

POINTERS

2-6

Background info
all data (variables/objects/arrays) processed by computer program sit in computer memory computer memory can be seen as a HUGE one-dimensional array
For example, can assume that each cell
0

stores 1 byte of data

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

each cell in this memory array has a unique index, normally referred to as address
2-7

Background info
When a function (e.g. main) starts to run, operating system (OS) allocates/assigns memory space to all declared variables, objects or arrays declared in this function
Assume, for simplicity, that each cell
0

stores 1 byte (8 bits) of data

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char a;

int j;

char arr[6];

Point p;

2-8

Background info
Values of variables/objects in the memory can be accessed (for example) using indexes (addresses) of the corresponding cells in the memory, if known
Assume, for simplicity, that each cell
0

stores 1 byte (8 bits) of data

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char a;
byte #12

int j;
bytes #20-23

char arr[6];
bytes #30-35

Point p;
bytes #37-44

2-9

Background info
Since variables/objects/arrays occupy consecutive cells in the memory, it is enough to know address of the first cell as long as we know the size of object/array
Assume, for simplicity, that each cell
0

stores 1 byte (8 bits) of data

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char a;
byte #12

int j;
4 bytes after #20

char arr[6];
6 bytes after #30

Point p;
8 bytes after #37

2-10

Address operator &


Operator & returns address (of the first cell) where variable/object is stored
cout << &a; cout << &j; cout <<&(arr[4]); cout <<&p;
0

=> => => =>

12 20 34 37

Clarification: typically, memory addresses are integers in hexadecimal format

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char a;

int j;

char arr[6];

Point p;

2-11

Pointers
Known location (address) of an object in the memory could be effectively used in coding
- e.g. passing address of a large object as function argument - more later

- Q: How can we store and manipulate objects addresses when coding - A: Use pointer variables (or simply pointers)
declaring pointer variables

char * s; int * t; Point * g;

Pointers
Pointer is a basic variable type very similar to integers value of any variable of pointer type is ONLY a memory address !!!
- that is, integer (in hexadecimal format)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char a;

int j;

char arr[6];

Point p;

Question:

int * t; // declaring pointer to int variable t t = &j; cout << t; // ???

Pointers
Like other types of variables/objects, pointer variables occupy some space in memory

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char a; int* t;

int j;

char arr[6];

Point p;

2-14

Pointers
Like other types of variables/objects, pointer variables occupy some space in memory
regardless of exact type (int*, char*, Point*, ) any pointer occupies the same amount of space
- e.g. 4 bytes in 32 bit Windows PCs (8 bytes in 64 bit Windows)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

2-15

Pointers
EXAMPLE:
s = &a; t = &j;
// value of pointer s is now 12 // value of pointer t is now 20 // but since t is a pointer to int, compiler knows that t points at // a chunk of 4 consecutive bytes 20-23 (with an int object) // value of pointer g is now 37 // but since g is a pointer to Point, compiler knows that g points at // a chunk of 8 consecutive bytes 37-44 (with a Point object)

g = &p;

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

12

20

37

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

2-16

Pointers
EXAMPLE:
s = &a; t = &j;
// value of pointer s is now 12 // value of pointer t is now 20 // but since t is a pointer to int, compiler knows that t points at // a chunk of 4 consecutive bytes 20-23 (with an int object) // value of pointer g is now 37 // but since g is a pointer to Point, compiler knows that g points at // a chunk of 8 consecutive bytes 37-44 (with a Point object)

g = &p;

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;
address of a chunk of memory for one char

char a; int* t;

int j;

char arr[6];

Point p; Point* g;
address of a 2-17 chunk of memory for one Point

address of a chunk of memory for one int

Pointers
Despite some similarity, pointer types have to be specialized for each class of objects
- to avoid mixing addresses of different types of objects
in order to properly access objects data from a given memory address, OS must know how many consecutive bytes to read and how to interpret them. Compiler obtains this information in operations with pointers from their specific type.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

variables of different types!!!

2-18

Pointers
EXAMPLE:
s = &a; // value of pointer s is now 12 (address determined by operator &) t = &j; // value of pointer t is now 20 w = &k; // value of pointer w is now 37

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6]; int k;

int* w;

variables of the same type

2-19

Pointers
EXAMPLE:
s = &a; // value of pointer s is now 12 (address determined by operator &) t = &j; // value of pointer t is now 20 w = &k; // value of pointer w is now 37 t = w; // value of pointer t is now 37 (copied from value of pointer w)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6]; int k;

int* w;

variables of the same type

2-20

Pointers
EXAMPLE:
s = &a; // value of pointer s is now 12 (address determined by operator &) t = &j; // value of pointer t is now 20 w = &k; // value of pointer w is now 37 t = w; // value of pointer t is now 37 (copied from value of pointer w) w = &j;
// value of pointer w is now 20 (address determined by operator &)

All these lines use basic copy operator =


0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6]; int k;

int* w;

variables of the same type

2-21

Copy Operator for Pointers


Works

as for all other basic types (int, float,) !!!

- copies (address) value evaluated in expression on the right hand side - pointer and expression on the r.h.s. should have the same type
char a, h, *c; // a way to declare pointer to char variable c char *s = &a; // as other types, pointers can be initialized at declaration c = &h; // operator & returns value of type char* (pointer to char) s = c;

EXAMPLE

int j, *w, *t; // a way to declare multiple pointers t = &j; // here, operator & returns value of type int* (pointer to int) s = t; NOTE: all pointers, e.g. s and t, have very similar c = &j;

looking integer values. Yet, compiler treats char* and int * variables as different types

Dereference Operator
Accessing (reading) data in memory
by variable/object name
int i = 5; // one integer object (4 bytes) is allocated
// in memory and its value is initialized to 5;

cout << i;

// value of i is extracted

2-23

Dereference Operator
Accessing (reading) data in memory
by memory address
int i = 5; // one integer object (4 bytes) is allocated
// in memory and its value is initialized to 5; int *t = &i; // one pointer (4 bytes) is allocated in memory and // initialized with address determined by operator & cout << *t; // address stored in t is extracted and // integer value (4 bytes) is read from // the corresponding location in the memory

Dereference operator *() tell the program to read data from address specified by expression on the right. (the known pointer-type
for expression on the right tells compiler how to read memory.)
2-24

Dereference Operator
Avoid confusion!
int a, *r; int *t = &a;

int j = *t; *t = a; in-front of expression containing previously declared pointer variables, symbol * indicates dereference operator
2-25

symbol * indicates pointer variable type in-front of any new variable name (inside declaration)

Pointers to Objects
Accessing objects in memory
by variable/object name
Point p(4,9);

p.shift_by(2,7); // shifts coordinates of a point by a vector cout << p.x; // value of x coordinate is extracted

2-26

Pointers to Objects
Accessing objects in memory
by memory address
Point p(4,9); Point *g = &p;

(*g).shift_by(2,7); // shifts coordinates of a point by a vector cout << (*g).x; // value of x coordinate is extracted

2-27

Pointers to Objects
Convenient syntax
- assume that value of expression a is objects address: e.g. Object * a = &object;

(*a).member_var <=> a->member_var (*a).member_fn() <=> a->member_fn()


2-28

Pointers to Objects
Point p(4,9); Point *g = &p; g->shift_by(2,7); cout << g->x; Point p(4,9); Point *g = &p; (*g).shift_by(2,7); cout << (*g).x;

MUST use this in assignments and exams


2-29

Pointer Arithmetic
s = &a; // 12 t = &j; // 20 g = &p; // 37

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

2-30

Pointer Arithmetic
s = &a; // 12 t = &j; // 20 g = &p; // 37 s = (s+1); t = (t+1); g = (g+1);
45: address of the next Point

w=w+1 increases value of pointer A *w; by sizeof(A)


13: address of the next char

24: address of the next int

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

NOTE: actual change of pointer value is determined by its exact type

2-31

Pointer Arithmetic
s = &a; // 12 t = &j; // 20 g = &p; // 37 s = (s-3); t = (t+2); g = (g+1);

w=w+int increases value of pointer A *w; by int*sizeof(A)


9 = 12-3*sizeof(char) 28 = 20+2*sizeof(int)

45 = 37+1*sizeof(Point)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

NOTE: actual change of pointer value is determined by its exact type

2-32

Pointer Arithmetic
s = &a; // 12 t = &j; // 20 g = &p; // 37 s -= 3; t += 2; g++;

w+=int increases value of pointer A *w; by int*sizeof(A)


9 = 12-3*sizeof(char) 28 = 20+2*sizeof(int)

45 = 37+1*sizeof(Point)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

NOTE: actual change of pointer value is determined by its exact type

2-33

Pointers and Array Names


declaration char arr[6]; implies that:
6 consecutive char cells are reserved in memory arr is a constant representing address of the first cell in this sequence (30)
- type of constant arr is compatible with char*
- arr has the same meaning as &arr[0] - *arr has the same meaning as arr[0]
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

2-34

Pointers and Array Names


EXAMPLE

s = arr; // is perfectly fine, copies address 30 from arr

cout << *(s+3);


dereference operator pointer arithmetic

cout << arr[3];

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

indexing into an array is really a pointer dereferencing operation

2-35

Pointers and Array Names


EXAMPLE

s = arr; // is perfectly fine, copies address 30 from arr *(s+2) = q;


dereference operator pointer arithmetic

arr[2]=q;

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

indexing into an array is really a pointer dereferencing operation

2-36

Pointers and Array Names


EXAMPLE

s = arr; // is perfectly fine, copies address 30 from arr s[2] = q; syntax allowed for pointers too!!!
0

arr[2]=q;

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

indexing into an array is really a pointer dereferencing operation

2-37

Pointers and Array Names


Note how standard operator[ ](int x) works for pointers: if p is a pointer variable (or expression), than p[x] gives the result of dereferencing *(p+x) for any integer x

e.g.

s[2] = q;

*(s+2)=q;

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

indexing into an array is really a pointer dereferencing operation

2-38

Pointers and Array Names

arr[2] = q;

*(arr+2)=q; syntax allowed for array names too!!!

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

indexing into an array is really a pointer dereferencing operation

2-39

Pointers and Array Names


EXAMPLE

s = arr; // is perfectly fine, copies address 30 from arr

A lot of similarity between pointers and array names!!!


-the latter are basically constant pointers (arr can not change its value 30) pointing at a reserved chunk of memory

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

2-40

illegal memory access


EXAMPLE

s = arr; // is perfectly fine, copies address 30 from arr *(s+8) = r; arr[8]=r;

Q: why is this bad???


0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

char* s;

char a; int* t;

int j;

char arr[6];

Point p; Point* g;

A: can ruin other objects in the memory


2-41 (if you code access memory illegally, random errors can occur at run-time)

illegal memory access


Accidental use of illegal address values
(pointing to either unreserved parts of memory or to

random cells inside unrelated objects) is

a very

common cause of bugs.

Code logic must avoid uncontrolled memory access


- e.g. check that array elements are read within the array bounds
2-42

NULL value for Pointers


Some basic recommendations
- never use uninitialized pointer variables - if pointer variable is not used in some part of your code, always set its value to NULL
(constant NULL is defined in all std header files)

int *s;

int *s = NULL;

..... .. s = &h;

.. ...... s = &h;
2-43

Pointers and Arrays of Objects


EXAMPLE 1 Point a[3]; // note: default constructor is used to initialize // each Point object in the array a[0].shift_by(3,7); a[2].x = -2;

// assuming x is public member

a[0]=(3,7)

a[1]=(0,0)

a[2]=(-2,0)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

Point a[3];

2-44

Pointers and Arrays of Objects


EXAMPLE 1 Point a[3]; // note: default constructor is used to initialize // each Point object in the array a[0].shift_by(3,7); a[2].x = -2;

// assuming x is public member

Point *p; p = a;

// is perfectly fine
a[0]=(3,7) a[1]=(0,0) a[2]=(-2,0)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

Point* p;

Point a[3];

2-45

Pointers and Arrays of Objects


EXAMPLE 1 Point a[3]; // note: default constructor is used to initialize // each Point object in the array a[0].shift_by(3,7); a[2].x = -2;

// assuming x is public member

Point *p; p = a; // is perfectly fine (*(p+1)).shift_by(1,4); (*(p+2)).y = 9;


0

a[0]=(3,7)

a[1]=(1,4)

a[2]=(-2,9)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

Point* p;

Point a[3];

2-46

Pointers and Arrays of Objects


EXAMPLE 1 Point a[3]; // note: default constructor is used to initialize // each Point object in the array a[0].shift_by(3,7); a[2].x = -2;

// assuming x is public member

Point *p; p = a; // is perfectly fine (p+1)->shift_by(1,4); (p+2)->y = 9;


0

a[0]=(3,7)

a[1]=(1,4)

a[2]=(-2,9)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

Point* p;

Point a[3];

2-47

Pointers and Arrays of Objects


EXAMPLE 1 Point a[3]; // note: default constructor is used to initialize // each Point object in the array a[0].shift_by(3,7); a[2].x = -2;

// assuming x is public member

Point *p; p = a; // is perfectly fine p[1].shift_by(1,4); p[2].y = 9;


0

a[0]=(3,7)

a[1]=(1,4)

a[2]=(-2,9)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

Point* p;

Point a[3];

2-48

Pointers and Arrays of Objects


Point a[3]; Point *p; p = a; ... ...

Syntax alert

(*(p+1)).shift_by(1,4); (*(p+2)).y = 9;

(p+1)->shift_by(1,4); (p+2)->y = 9;

p[1].shift_by(1,4); p[2].y = 9;

All 3 blocks contain equivalent code


2-49

Pointers and Arrays of Objects


EXAMPLE 2 Point a[3]; // note: default constructor is used to initialize // each Point object in the array a[0].shift_by(3,7); a[2].x = -5;

// assuming x is public member

-5 ?
0

Point *p = (a+2); cout << p->x;

// can use pointer arithmetic // same as cout << (*p).x;


a[2]=(-5,0)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

Point* p;

Point a[3];

2-50

Pointers and Arrays of Objects


EXAMPLE 2 Point a[3]; // note: default constructor is used to initialize // each Point object in the array a[0].shift_by(3,7); a[2].x = -5;

// assuming x is public member

-5
0

Point *p = (a+2); cout << p[0].x;

// can use pointer arithmetic // same as cout << (*p).x;


p[0]= a[2]=(-5,0)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

Point* p;

Point a[3];

2-51

Call-by-reference and Pointers


void negate(int& x) { x = -x; } void main() { int b = 5; negate(b); } void negate(int *x) { *x = -(*x); } void main() { int b = 5; negate(&b); }

Formal argument of negate (pointer x) is initialized from the This call-by-reference syntax actual argument: value of only hides the use of memory expression &b. Such call-by-value addresses (pointer values), for pointer x allows negate to made explicit on the right modify value of variable2-52 b.

Call-by-reference and Pointers


Using pointers to objects as function arguments allows: to avoid copying large amounts of data to modify objects very similar properties to call-by-reference (call-by-reference only hides using pointers)

In this course, we will explicitly use pointers as function arguments in order to emphasize 2-53 understanding of memory access operations

Part II

DYNAMIC MEMORY ALLOCATION


2-54

Statically Allocated Objects


Up to now all local and global variables/objects that weve used have been statically allocated
global variables/objects exist in the memory for the whole duration of your program local variables/object exist in the memory only while specific function where they are declared is executed
- such objects disappear when this function exits

2-55

Statically Allocated Objects


Up to now all local and global variables/objects that weve used have been statically allocated
the number of static objects is fixed in the code (each time the program is compiled) and it can not change at run time

Practical applications that can be coded using ONLY static variables is very limited (mostly toy examples)!
2-56

Need for Dynamic Objects


Example: internet browser
browser creates image objects in the memory on-the-fly when a user clicks on a new web page with pictures.

The number of image objects that will be allocated in your computers memory is not known when the browsers code is compiled. How would Firefox or Microsoft know?!

157

Need for Dynamic Objects


Inside PowerPoints code, dynamic objects had to be created when making this slide...
start end

void Slide::onMouseDrag(Point start, Point end) { if (theArrowButton.isSelected()) { ArrowShape* arrow = new ArrowShape(start,end); m_shapes.add(arrow); } if (theCircleButton.isSelected()) { ...etc... } }

C++ code would look something like this...


158

Dynamic vs. Static Objects


Programs can create objects dynamically (on-the-fly) Dynamic objects can stay (persist) in the memory even after exit from the function that created them Dynamic objects are created ONLY using operator new Dynamic objects remain in Point * get_random_point() { Point *s = new Point(rand(),rand()); memory until the program return s; ends, unless we explicitly Dynamically allocated Point } delete them void main (bool yes) {

Dynamic objects can be accessed ONLY using pointers

Statically allocated Point Point c; Point *p = NULL; if (yes) p = get_random_point(); .... if (p!=NULL) delete p; .... 2-59 Releasing memory of dynamic Point

Operators new and delete


Operator new Obj()
- requests OS to allocate/reserve memory for an object of specified type/class Obj - initializes it using specified constructor arguments - returns address of that object
Point *s = new Point(1,4); Point * t = new Point; int * i = new int; char * c = new char(t);

- created dynamic objects sit in memory until explicitly deleted by operator delete

2-60

Operators new and delete


Operator delete addr
- calls destructor for an object whose address is specified by expression on the right hand side - requests OS to de-allocate memory for this object - only address of dynamic object is allowed, that is, address previously returned by operator new
Point *s = new Point(1,4); Point p(2,3); delete s; s = &p; delete s;
2-61

Operators new and delete


Operator delete addr
- for objects of any class Obj, the destructor ~Obj() is never called explicitly!!! - delete determines the kind of object addr points at (from specific pointer type of expression addr), and calls the destructor for this class of objects - if addr is specified by a pointer variable, it is safer to change its value (e.g. to NULL) since accidental use of de-allocated memory address is dangerous
Point *s = new Point(1,4); ... delete s; s = NULL;
2-62

Call Stack vs. Heap


Room for static variables/objects is in an area of memory known as the call stack Dynamic variables/objects are allocated in a different area of memory - heap
2-63

Call Stack vs. Heap


int j = 4; int *w = &j; Point *s = new Point(1,4); Point a[3]; int * k = new int(3);

static array of objects

int j;
4

int *w; Point *s; int *k;

Point a[3];
(0,0) (0,0)

call stack
(0,0)

heap
(1,4) 3

static objects

dynamic objects

2-64

Memory Diagrams
Through out the course, we will use simplified memory diagrams illustrating the state of variables/objects and pointers in the memory after executing given code
Example 1
int a=10, b=3; int * s; s = &a;

call stack

heap

10 a

3
b
2-65

Memory Diagrams
Through out the course, we will use simplified memory diagrams illustrating the state of variables/objects and pointers in the memory after executing given code
Example 1
int a=10, b=3; int * s; s = &a; s = new int;

call stack

heap

10 a

3 s b

2-66

Memory Diagrams
Through out the course, we will use simplified memory diagrams illustrating the state of variables/objects and pointers in the memory after executing given code
Example 1
int a=10, b=3; int * s; s = &a; s = new int; *s = 6;

call stack

heap

10 a

3 s b

2-67

Memory Diagrams
Through out the course, we will use simplified memory diagrams illustrating the state of variables/objects and pointers in the memory after executing given code
Example 2
Point b[3]; Point *s = new Point(1,3);

call stack s

heap
(1,3)

(0,0) (0,0) (0,0)


b
2-68

Memory Diagrams
Through out the course, we will use simplified memory diagrams illustrating the state of variables/objects and pointers in the memory after executing given code
Example 2
Point b[3]; Point *s = new Point(1,3); s->y = 5;

call stack s

heap
(1,5)

(0,0) (0,0) (0,0)


b
2-69

Memory Diagrams
Through out the course, we will use simplified memory diagrams illustrating the state of variables/objects and pointers in the memory after executing given code
Example 2
Point b[3]; Point *s = new Point(1,3); s->y = 5; s = b-1;

call stack s

heap
(1,5)

??? (0,0) (0,0) (0,0)


b
2-70

Memory Diagrams
Through out the course, we will use simplified memory diagrams illustrating the state of variables/objects and pointers in the memory after executing given code
Example 2
Point b[3]; Point *s = new Point(1,3); s->y = 5; s = b-1; *(s+2) = Point(7,9);

call stack s

heap
(1,5)

??? (0,0) (7,9) (0,0)


b

Memory Diagrams
Through out the course, we will use simplified memory diagrams illustrating the state of variables/objects and pointers in the memory after executing given code
Example 2
Point b[3]; Point *s = new Point(1,3); s->y = 5; s = b-1; *(s+2) = Point(7,9); (s+1)->shift_by(2,4);

call stack s

heap
(1,5)

??? (2,4) (7,9) (0,0)


b
2-72

Memory Diagrams
Through out the course, we will use simplified memory diagrams illustrating the state of variables/objects and pointers in the memory after executing given code
Example 2
Point b[3]; Point *s = new Point(1,3); s->y = 5; s = b-1; *(s+2) = Point(7,9); (s+1)->shift_by(2,4); s[1].shift_by(1,1);

call stack s

heap
(1,5)

??? (3,5) (7,9) (0,0)


b
2-73

Memory Diagrams
Through out the course, we will use simplified memory diagrams illustrating the state of variables/objects and pointers in the memory after executing given code
Example 2
Point b[3]; Point *s = new Point(1,3); s->y = 5; s = b-1; *(s+2) = Point(7,9); (s+1)->shift_by(2,4); s[1].shift_by(1,1); s[3] = Point(8,6);

call stack s

heap
(1,5)

??? (3,5) (7,9) (8,6)


b
2-74

now s[i] is an array with valid range i=1,2,3

Array of Pointers to Objects


Array of pointers can store addresses of a sequence of dynamically allocated objects
Point * r[4]; r[0] = new Point(2,3); r[1] = new Point(); r[2] = NULL; r[3] = new Point(4,5);

call stack

heap

(2,3)
(0,0)
NULL

(4,5)
2-75

Array of Pointers to Objects


Array of pointers can store addresses of a sequence of dynamically allocated objects
Point * r[4]; r[0] = new Point(2,3); r[1] = new Point(); r[2] = NULL; r[3] = new Point(4,5); delete r[0];

call stack

heap (2,3)

(0,0)
NULL

(4,5)
2-76

Array of Pointers to Objects


Array of pointers can store addresses of a sequence of dynamically allocated objects
Point * r[4]; r[0] = new Point(2,3); r[1] = new Point(); r[2] = NULL; r[3] = new Point(4,5); delete r[0]; r[0] = NULL;

call stack

heap (2,3)

(0,0)
NULL NULL

(4,5)
2-77

Array of Pointers to Objects


Array of pointers can store addresses of a sequence of dynamically allocated objects
Point * r[4]; r[0] = new Point(2,3); r[1] = new Point(); r[2] = NULL; r[3] = new Point(4,5); delete r[0]; r[0] = NULL; r[3]->shift_by(1,1);
NULL

call stack

heap

(2,3)
(0,0)
NULL

(5,6)
2-78

Syntax Alert
Pointers and arrays of objects
(slides 43-50) Point a[3]; Point *p; p = a; . . p[1].shift_by(1,4); p[2].y = 9; p[2]->y = 2;

Arrays of pointers to objects


(slides 74-77) Point * r[3]; r[0] = new Point(); r[1] = new Point(); r[2] = new Point(); . r[1]->shift_by(1,4); r[2]->y = 9; r[2].y = 2;

Correct syntax (a.member or a->member) always depends on the type of expression a (is it Obj or a pointer Obj*?)

Syntax Alert
Pointers and arrays of objects
(slides 43-50) Point a[3]; Point *p; p = a; . . p[1].shift_by(1,4); p[2].y = 9; p[2]->y = 2; (p+2)->y = 2; // is OK

Arrays of pointers to objects


(slides 74-77) Point * r[3]; r[0] = new Point(); r[1] = new Point(); r[2] = new Point(); . r[1]->shift_by(1,4); r[2]->y = 9; r[2].y = 2;

Correct syntax (a.member or a->member) always depends on the type of expression a (is it Obj or a pointer Obj*?)

Deleting Dynamic Objects


and typical mistakes in exams/assignments
Example 1
Card * c = new Card(); .... ..... delete &c; // WRONG

Example 2
Card * c = new Card(); .... ..... c->~Card(); // WRONG

Correct version
Card * c = new Card(); .... ..... ?

address of a static point variable


value of expression after delete should be address of dynamic object to be deleted

destructor can not be called explicitly

call stack

heap (H,6)

2-81

Deleting Dynamic Objects


and typical mistakes in exams/assignments
Example 1
Card * c = new Card(); .... ..... delete &c; // WRONG

Example 2
Card * c = new Card(); .... ..... c->~Card(); // WRONG

Correct version
Card * c = new Card(); .... ..... delete c; // GOOD

address of a static point variable


value of expression after delete should be address of dynamic object to be deleted

destructor can not be called explicitly

call stack

heap (H,6)

Deleting Dynamic Objects


and typical mistakes in exams/assignments
Example 1
Card * c = new Card(); .... ..... delete &c; // WRONG

Example 2
Card * c = new Card(); .... ..... c->~Card(); // WRONG

Correct version
Card * c = new Card(); .... ..... delete c; // GOOD c = NULL; // GOOD

address of a static point variable


value of expression after delete should be address of dynamic object to be deleted

destructor can not be called explicitly

call stack
NULL

heap (H,6)

Deleting Dynamic Objects


and typical mistakes in exams/assignments
Example 3
Card * c = new Card(); .... .....

call stack

heap
(H,6)

2-84

Deleting Dynamic Objects


and typical mistakes in exams/assignments
Example 3
Card * c = new Card(); .... ..... c = NULL; // MEMORY LEAK delete c;

call stack
NULL

heap
(H,6)

MEMORY LEAK: dynamic object still occupies memory but NONE of the pointers keeps its address 2-85

Deleting Dynamic Objects


and typical mistakes in exams/assignments
Example 3
Card * c = new Card(); .... ..... c = NULL; // MEMORY LEAK delete NULL; // Why?!

call stack
NULL

heap
(H,6)

MEMORY LEAK: dynamic object still occupies memory but NONE of the pointers keeps its address 2-86

From Dynamic Objects to Dynamic Arrays


Up to now all arrays that weve used have been statically allocated
Point c[4]; - such arrays have very rigid life cycle (they exists in
memory only within the scope of their declaration, e.g. local static vars disappear at the end of function where they are declared)

- the size of static arrays is fixed (each time you compile your program), it can not change at run time. Point c[k];
2-87

Need for Dynamic Arrays


Example: internet browser
browser allocates an array of pixels in the memory for each image on a web page The size of pixels array that needs to be allocated for each image can not be known when browser code compiled. How would Firefox or Microsoft know?!

188

Dynamic vs. Static Arrays


Programs can create arrays dynamically (on-the-fly) Dynamic arrays can stay (persist) in the memory even after exit from the function that created it Dynamic arrays are created ONLY using operator new [ ] Dynamic objects remain in Point * get_array(int size) { Point *s = new Point [size]; memory until the program return s; ends, unless we explicitly Dynamically allocated array } delete [ ] them void main (int k) {

Dynamic arrays can be accessed ONLY using pointers

Statically allocated array Point c[4]; Point *p = NULL; if (k>0) p = get_array(k); .... if (p!=NULL) delete [ ] p; .... 2-89 Releasing memory of dynamic array

Dynamic vs. Static Arrays


int j = 4; int *w = &j; Point *s = new Point(1,4); Point a[3];

static array of objects

int j;
4

int *w; Point *s;

Point a[3];
(0,0) (0,0)

call stack
(0,0)

heap
(1,4)

static objects

dynamic object

2-90

Dynamic vs. Static Arrays


int j = 4; int *w = &j; Point *s = new Point(1,4); Point *a = new Point[3];

int j;
4

int *w; Point *s; Point * a;

call stack

heap
(1,4) (0,0) (0,0) (0,0)

static objects

dynamic object

2-91 dynamic array of objects

Dynamic vs. Static Arrays


One major difference between dynamically and statically allocated arrays

void func(int k) { ..... Point c[5]; Point *p = new Point [k]; .... Size of dynamic array may vary } at different run-times depending 2-92 on arguments value

Size of any static array must be known at compile time

Dynamic vs. Static Arrays


One major difference between dynamically and statically allocated arrays

void func(int k) { ..... Point c[k]; Point *p = new Point [k]; .... Size of dynamic array may vary } at different run-times depending 2-93 on arguments value

Size of any static array must be known at compile time

Operators new [ ] and delete [ ]


Operator new Obj [int]
- requests OS to allocate/reserve memory (in heap) for a given size array of objects of class Obj - initializes all objects using default constructor - returns address of the first object in the array
Point *s = new Point[k]; int * i = new int[5]; char * c = new char[k+3];
WARNING: integer value inside [...] should be positive. E.g., in case of code like float * f = new float[0]; dereferencing f will be undefined and could lead to a run-time error

- created dynamic array of objects sits in memory until explicitly deleted by operator delete [ ] 2-94

Operators new [ ] and delete [ ]


Operator delete [ ] addr
- calls destructor for all objects in the array, address of the first object in the array must be specified - requests OS to de-allocate memory for this array - only address of dynamic array is allowed (that is, address previously generated by operator new [ ])
Point *s = new Point[k]; Point p[4]; delete [ ] s; delete [ ] p; s = p; delete [ ] s;

2-95

Operator delete vs. delete [ ]


Dynamic objects Dynamic arrays of allocated by operator objects allocated by new can be freed ONLY operator new [] can be by operator delete freed ONLY by delete []
Point *p; p = new Point(3,8); delete [ ] p; Rect *r; r = new Rect [k]; delete r;

2-96

Operator delete vs. delete [ ]


Dynamic objects Dynamic arrays of allocated by operator objects allocated by new can be freed ONLY operator new [] can be by operator delete freed ONLY by delete []
Point *p; p = new Point(3,8); delete p; Rect *r; r = new Rect [k]; delete [ ] r;

2-97

Part III

EXAMPLES OF DYNAMIC ARRAYS


2-98

Objects can hide dynamic arrays


explicit use of dynamic array allocation
inside some function

dynamic memory operations hide inside DynArray code


inside some function

char *a = new char[3]; a[0]=c; a[1]=a; a[2] =t; delete [ ] a;

DynArray a(3); a[0]=c; a[1]=a; a[2] =t;

call stack

heap

call stack

heap c a t
2-99

c
a

t a
3

Objects can hide dynamic arrays


inside DynArray.h class DynArray { private: int m_size; char * m_container; public: DynArray(int w); ~DynArray(); char& operator[ ](int x); } DynArray::DynArray(int w) { m_size = w; m_container = new char[w]; } DynArray ::~ DynArray() { delete [ ] m_container; } char& DynArray :: operator[ ](int x) { return m_container[x]; } inside DynArray.cpp

dynamic memory operations hide inside DynArray code


inside some function

DynArray a(3); // hides dynamic memory allocation a[0]=c; a[1]=a; a[2] =t; // works like a.m_container[2]=t;

call stack c

heap a t
2-100

Array of Pointers to Dynamic Array vs. Dynamic Objects of Objects


Point *a[3]; a[0] = new Point(1,2); a[1] = NULL; a[2] = new Point(7,4); Point *b = new Point[3];

call stack a
NULL

heap (1,2)

call stack

heap (0,0) (0,0) (0,0)

(7,4)

2-101

Array of Pointers to Dynamic Array vs. Dynamic Objects of Objects


Point *a[3]; a[0] = new Point(1,2); a[1] = NULL; a[2] = new Point(7,4); Point *b = new Point[3]; b[0] = Point(1,2); b[2] = Point(7,4);

call stack a
NULL

heap (1,2)

call stack

heap (1,2) (0,0) (7,4)

(7,4)

2-102

Array of Pointers to Dynamic Array vs. Dynamic Objects of Objects


Point *a[3]; ... ... delete a[0]; Point *b = new Point[3]; ... ... delete [ ] b;

call stack a
NULL

heap (1,2)

call stack

heap (1,2) (3,5) (7,4)

(7,4)

2-103

Array of Pointers to Dynamic Array vs. Dynamic Objects of Objects


Point *a[3]; ... ... delete a[0]; a[0] = NULL; Point *b = new Point[3]; ... ... delete [ ] b; b=NULL;

call stack a
NULL NULL

heap (1,2)

call stack

heap (1,2) (3,5) (7,4)

NULL

(7,4)

2-104

Dynamic Array of Pointers


Can use dynamic arrays of pointers
- instead of static array of pointers on the previous slide (left side) - advantage: capacity of dynamic array can be decided at run time

?
Point *a[3]; a[1] = new Point(3,5); Point **a = new Point*[3]; a[0] = new Point(1,2);

call stack a

heap (1,2)

call stack

heap

(3,5) (7,4)

a
(1,2) (3,5)

(7,4)
2-105

Double Pointers
A pointer can also store address of other pointer variables
-a
is a pointer to pointer
(a.k.a. double pointer)
equivalent code Point **a = new Point*[3]; a[0] = new Point(1,2);

a[2]->x = 7; a[0]->shift_by(1,2);
*(a[2]).x = 7; *(a[0]).shift_by(1,2);

call stack

heap

a
(1,2) (3,5)

*(*(a+2)).x = 7; *(*a).shift_by(1,2);

(7,4)
2-106

Double Pointers
call stack
Point **a; //declaration

heap

2-107

Double Pointers
call stack
Point **a; //declaration a = new Point *;

heap

2-108

Double Pointers
call stack
Point **a; //declaration a = new Point *; *a = new Point(3,4);

heap

(3,4)

2-109

Double Pointers
call stack
Point **a; //declaration a = new Point *; *a = new Point(3,4); .... delete *a;

heap

(3,4)

2-110

Double Pointers
call stack
Point **a; //declaration a = new Point *; *a = new Point(3,4); .... delete *a; delete a;

heap

(3,4)

2-111

Double Pointers
call stack
Point **a; //declaration a = new Point *; *a = new Point(3,4); .... delete *a; delete a; a = NULL;

heap

NULL

(3,4)

2-112

Dynamic 2D arrays (Ex.1)


dynamic allocation & deallocation of 2D array of size 3x2

call stack
Point **a; //declaration

heap

2-113

Dynamic 2D arrays (Ex.1)


dynamic allocation & deallocation of 2D array of size 3x2

call stack
Point **a; //declaration a = new Point* [3];

heap

?
2-114

Dynamic 2D arrays (Ex.1)


dynamic allocation & deallocation of 2D array of size 3x2

call stack
Point **a; //declaration a = new Point* [3]; for (int i=0; i<3; i++) a[i] = new Point[2];

heap

(0,0) (0,0)
(0,0) (0,0)

a
(0,0) (0,0)

2-115

Dynamic 2D arrays (Ex.1)


dynamic allocation & deallocation of 2D array of size 3x2

call stack
Point **a; //declaration a = new Point* [3]; for (int i=0; i<3; i++) a[i] = new Point[2]; a[2][1].x = 5;

heap

(0,0) (0,0)
(0,0) (0,0)

a
(0,0) (5,0)

2-116

Dynamic 2D arrays (Ex.1)


dynamic allocation & deallocation of 2D array of size 3x2

call stack
Point **a; //declaration a = new Point* [3]; for (int i=0; i<3; i++) a[i] = new Point[2]; a[2][1].x = 5; a[1][0].shift_by(2,3);

heap

(0,0) (0,0)
(2,3) (0,0)

a
(0,0) (5,0)

2-117

Dynamic 2D arrays (Ex.1)


dynamic allocation & deallocation of 2D array of size 3x2

call stack
Point **a; //declaration a = new Point* [3]; for (int i=0; i<3; i++) a[i] = new Point[2]; a[2][1].x = 5; a[1][0].shift_by(2,3); a[0][1] = Point(6,9);

heap

(0,0) (6,9)
(2,3) (0,0)

a
(0,0) (5,0)

2-118

Dynamic 2D arrays (Ex.1)


dynamic allocation & deallocation of 2D array of size 3x2

call stack
Point **a; //declaration a = new Point* [3]; for (int i=0; i<3; i++) a[i] = new Point[2]; a[2][1].x = 5; a[1][0].shift_by(2,3); a[0][1] = Point(6,9);

heap

(0,0) (6,9)
(2,3) (0,0)

a
(0,0) (5,0)

for (i=0; i<3; i++) delete [ ] a[i];


2-119

Dynamic 2D arrays (Ex.1)


dynamic allocation & deallocation of 2D array of size 3x2

call stack
Point **a; //declaration a = new Point* [3]; for (int i=0; i<3; i++) a[i] = new Point[2]; a[2][1].x = 5; a[1][0].shift_by(2,3); a[0][1] = Point(6,9);

heap

(0,0) (6,9)
(2,3) (0,0)

a
(0,0) (5,0)

for (i=0; i<3; i++) delete [ ] a[i]; delete [ ] a;


2-120

Dynamic 2D arrays (Ex.1)


dynamic allocation & deallocation of 2D array of size 3x2

call stack
Point **a; //declaration a = new Point* [3]; for (int i=0; i<3; i++) a[i] = new Point[2];
NULL

heap

allocation

(0,0) (6,9)
(2,3) (0,0) (0,0) (5,0)

a[2][1].x = 5; a[1][0].shift_by(2,3); a[0][1] = Point(6,9);

deallocation

use

for (i=0; i<3; i++) delete [ ] a[i]; delete [ ] a; a = NULL;

2-121

Dynamic 2D arrays (Ex.2)


dynamic allocation & deallocation of 2D array of size 3x2

Point **a;

//declaration

heap

call stack

?
a
2-122

Dynamic 2D arrays (Ex.2)


dynamic allocation & deallocation of 2D array of size 3x2

Point **a; //declaration a = new Point* [3];

heap

call stack

?
2-123

Dynamic 2D arrays (Ex.2)


dynamic allocation & deallocation of 2D array of size 3x2

Point **a; //declaration a = new Point* [3]; a[0] = new Point[6];

heap

(0,0) (0,0) (0,0) (0,0) (0,0) (0,0)

call stack

?
2-124

Dynamic 2D arrays (Ex.2)


dynamic allocation & deallocation of 2D array of size 3x2

Point **a; //declaration a = new Point* [3]; a[0] = new Point[6]; for (int i=1; i<3; i++) a[i] = a[i-1]+2;

heap

(0,0) (0,0) (0,0) (0,0) (0,0) (0,0)

call stack

a[0]

a[1]

a[2]

2-125

Dynamic 2D arrays (Ex.2)


dynamic allocation & deallocation of 2D array of size 3x2

Point **a; //declaration a = new Point* [3]; a[0] = new Point[6]; for (int i=1; i<3; i++) a[i] = a[i-1]+2;

heap
a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1]

(0,0) (6,9) (2,3) (0,0) (0,0) (5,0)

a[2][1].x = 5; a[1][0].shift_by(2,3); a[0][1] = Point(6,9);

call stack

a[0]

a[1]

a[2]

2-126

Dynamic 2D arrays (Ex.2)


dynamic allocation & deallocation of 2D array of size 3x2

Point **a; //declaration a = new Point* [3]; a[0] = new Point[6]; for (int i=1; i<3; i++) a[i] = a[i-1]+2;

heap

(0,0) (6,9) (2,3) (0,0) (0,0) (5,0)

a[2][1].x = 5; a[1][0].shift_by(2,3); a[0][1] = Point(6,9); delete [ ] a[0];

call stack

a[0]

a[1]

a[2]

2-127

Dynamic 2D arrays (Ex.2)


dynamic allocation & deallocation of 2D array of size 3x2

Point **a; //declaration a = new Point* [3]; a[0] = new Point[6]; for (int i=1; i<3; i++) a[i] = a[i-1]+2;

heap

(0,0) (6,9) (2,3) (0,0) (0,0) (5,0)

a[2][1].x = 5; a[1][0].shift_by(2,3); a[0][1] = Point(6,9); delete [ ] a[0]; delete [ ] a;

call stack

a
2-128

Dynamic 2D arrays (Ex.2)


dynamic allocation & deallocation of 2D array of size 3x2

Point **a; //declaration a = new Point* [3]; a[0] = new Point[6]; for (int i=1; i<3; i++) a[i] = a[i-1]+2;

heap

allocation

(0,0) (6,9) (2,3) (0,0) (0,0) (5,0)

a[2][1].x = 5; a[1][0].shift_by(2,3); a[0][1] = Point(6,9); delete [ ] a[0]; delete [ ] a; a = NULL;

use

call stack
NULL

deallocation

Dynamic 2D arrays (Ex.2)


dynamic allocation & deallocation of 2D array of size 3x2

heap

Question:
Is it possible to avoid one extra array storing addresses of columns?

a[0][0]

a[0][1]

a[1][0]

a[1][1]

a[2][0]

a[2][1]

(0,0) (6,9) (2,3) (0,0) (0,0) (5,0)

call stack

a[0]

a[1]

a[2]

2-130

Dynamic 2D arrays (Ex.3)


inside Table2D_float.h inside Table2D_float.cpp

class Table2D {

public: Table2D(int w, int h); ~Table2D();


overloaded operator

Table2D::Table2D(int w, int h) { m_width = w; m_height = h; m_data = new float[w*h]; for (int i=0; i<w*h; i++) m_data[i]=0; }
Table2D::~Table2D() { delete [ ] m_data; }
returns address of the x-th column

float * operator[ ] (int x);


private: int m_width; int m_height; float * m_data; }

float * Table2D::operator[ ] (int x) { return m_data + x*m_height; } computed using pointer arithmetic

Dynamic 2D arrays (Ex.3)


dynamic allocation & deallocation of 2D array of size 3x2

main() { Table2D a(3,2); // declaration ... ... constructor allocates memory in the heap

heap

call stack
Table2D::Table2D(int w, int h) { m_width = w; m_height = h; m_data = new float[w*h]; for (int i=0; i<w*h; i++) m_data[i]=0; }

3
a

2
2-132

m_data m_width m_height

Dynamic 2D arrays (Ex.3)


dynamic allocation & deallocation of 2D array of size 3x2

main() { Table2D a(3,2); // declaration a[2][1] = 7.1; ...

heap

0
NOTE: (a[x]) [y] = *(a[x] +y )
applying standard operator [ ] (see p. 2-38) to a pointer returned by overloaded operator [ ] for object a

7.1

call stack

a[2]

m_data+2*m_height

3
a

2
2-133

m_data m_width m_height

Dynamic 2D arrays (Ex.3)


dynamic allocation & deallocation of 2D array of size 3x2

main() { Table2D a(3,2); // declaration a[2][1] = 7.1; ...

heap
column 0

column 1

column 2

0
NOTE: (a[x]) [y] = *(a[x] +y )
applying standard operator [ ] (see p. 2-38) to a pointer returned by overloaded operator [ ] for object a

7.1

call stack

3
a

2
2-134

m_data m_width m_height

a[2]

m_data+2*m_height
address of column 2

Dynamic 2D arrays (Ex.3)


dynamic allocation & deallocation of 2D array of size 3x2

main() { Table2D a(3,2); // declaration a[2][1] = 7.1; ...

heap
column 0
a[0][0] a[0][1]

column 1
a[1][0] a[1][1]

column 2
a[2][0] a[2][1]

0
NOTE: (a[x]) [y] = *(a[x] +y )
applying standard operator [ ] (see p. 2-38) to a pointer returned by overloaded operator [ ] for object a

7.1

call stack

3
a

2
2-135

m_data m_width m_height

a[2] = m_data+2*m_height a[2][1] = *(m_data+2*m_height +1)

Dynamic 2D arrays (Ex.3)


dynamic allocation & deallocation of 2D array of size 3x2

main() { Table2D a(3,2); // declaration a[2][1] = 7.1; } // destructor for a is called

heap
column 0
a[0][0] a[0][1]

column 1
a[1][0] a[1][1]

column 2
a[2][0] a[2][1]

7.1

Table2D::~Table2D() { delete [ ] m_data; }

call stack

3
a

2
2-136

m_data m_width m_height

Dynamic 2D arrays (Ex.3)


dynamic allocation & deallocation of 2D array of size 3x2

main() { Table2D a(3,2); // declaration a[2][1] = 7.1; } // destructor for a is called

heap

7.1

Table2D::~Table2D() { delete [ ] m_data; } This code is run just before object a is removed from the memory (in call stack)

call stack

3
a

2
2-137

m_data m_width m_height

Objects with Dynamic arrays


every Point object only needs 8 bytes
main() { Point a(2,3); //declaration Point b(4,8); }

each Image object needs different amount of memory


main() { Image a(100,200); Image b(300,450); }
//declaration

Point::Point(int x, int y) { m_x=x; m_y=y; }


Point::~Point() { cout << deleted one point; }

Image::Image(int w, int h) { m_width = w; m_height = h; m_pixels = new int[w*h*3]; //RGB } Image::~Image() { delete [ ] m_pixels; }

2-138

Vous aimerez peut-être aussi