86
1 Department of Computer Science and Engineering, HKUST HKUST Summer Programming Course 2008 Pointers and References ~ Pointers, Memory Allocation and References

HKUST Summer Programming Course 2008

  • Upload
    brandy

  • View
    23

  • Download
    0

Embed Size (px)

DESCRIPTION

HKUST Summer Programming Course 2008. Pointers and References ~ Pointers, Memory Allocation and References. Overview. Pointers What are Pointers? Declaration of Pointer Variables Pointer Operator - & (Address-Of) Pointer Operator - * (Dereference) The Different Uses of Operator * - PowerPoint PPT Presentation

Citation preview

Page 1: HKUST Summer Programming Course 2008

1Department of Computer Science and Engineering, HKUST

HKUST SummerProgramming Course 2008

Pointers and References

~ Pointers, Memory Allocation and References

Page 2: HKUST Summer Programming Course 2008

2

Overview Pointers

What are Pointers? Declaration of Pointer Variables Pointer Operator - & (Address-Of) Pointer Operator - * (Dereference) The Different Uses of Operator * Pointer Assignments Pointer Arithmetic Pointer Comparisons Multiple Indirection (Pointer to Pointer) Arrays and Pointers Dereference Array Pointers Array of Pointers Const and Pointer Null Pointer void Pointer

Page 3: HKUST Summer Programming Course 2008

3

Overview Memory Allocation

Static and Dynamic Allocation De-allocation of Memory Allocating and De-allocating Dynamic Arrays Illegal Delete on Dynamic Arrays Dangling Pointer Memory Leakage

References What are References? The Different Uses of Operator & Call by Reference Pointer vs. Reference Return-by-Reference

Page 4: HKUST Summer Programming Course 2008

4Department of Computer Science and Engineering, HKUST

Pointers and References

Pointers

Page 5: HKUST Summer Programming Course 2008

5

What are Pointers?

A pointer or pointer variable is a VARIABLE that holds a memory address of another object (typically another variable) in memory.

‘ a’‘ a’

MemoryAddress

1000

1012

10041008

1016

Variables inmemory

1020

Memory

10001000

If one variable contains the address of another variable, the first variable is said to point to the second.

Pointer / Pointer variable

Page 6: HKUST Summer Programming Course 2008

6

Declaration of Pointer Variables If a variable is going to hold an address of another variable,

it must be declared as follows.

SYNTAX:<type>* <name>; OR<type> *<name>;

where type is the type of variable that this pointer variablecan point to (e.g. int, char, double, user-defined type).The name is the name of the pointer variable.

Actually, we can treat <type>* as a special type which is a pointer type.

Page 7: HKUST Summer Programming Course 2008

7

Example

// declare a pointer that points to a variable of int type

int* a; // the value of a is undefined and contains garbage.

// declare a pointer that points to a variable of double type

double* b; // the value of b is undefined and contains garbage.

// declare a pointer that points to a variable of char type

char* c; // the value of c is undefined and contains garbage.

// there is no difference for you to put * close to type

// OR close to name

int* d; // the value of d is undefined and contains garbage.

int *d;

Page 8: HKUST Summer Programming Course 2008

8

Pointer Operator - & (Address-Of) There are two special operators for pointers: & and * The first operator, & is a unary operator that returns the memory

address of another variable. Usage: &<variable_name>

We can think of & as returning “the address of”.

Example:// pint receives the address of var1int var1 = 5;int* pint = &var1;

// pdouble receives the address of var2double var2 = 1.23;double* pdouble = &var2;

// ERROR: pdouble2 must point to a variable of type doubledouble* pdouble2 = &var1;

Page 9: HKUST Summer Programming Course 2008

9

Pointer Operator - & (Address-Of)

Graphic representation of last example

55

10001000

10121012

MemoryAddress

1000

1012

1004

1008

Variables inmemory

Memory

1.231.23

VariablesName

pdouble

pint

var2

var1

1016

Page 10: HKUST Summer Programming Course 2008

10

Example - & (Address-Of)

#include <iostream>

using namespace std;

int main(){

int a, b;

a = 88;

b = 100;

cout << "The address of a is: " << &a << endl;

cout << "The address of b is: " << &b << endl;

return 0;

}

……

8888

100100

MemoryAddress

1000

1012

10041008

Variables inmemory

Memory

……

VariablesName

ba

Output:The address of a is: 1004The address of b is: 1008

Page 11: HKUST Summer Programming Course 2008

11

Pointer Operator - * (Dereference) The second operator, *, is the complement of operator

&. It is also a unary operator that accesses the value

located at the address that it points to. We can think of * as “at address”.

Example:int var1 = 5; // if (&var1) = 1004int* pint = &var1; // pint points to var1 (then, pint = 1004)

// var2 receives the value at address pint (var2 = 5).int var2 = *pint;

// change the value of the memory location pointed to by pint // to 10, therefore var1=10, but note that var2=5*pint = 10;

Page 12: HKUST Summer Programming Course 2008

12

Pointer Operator - * (Dereference)

Graphic representation of last example

5 105 10

10001000

55

MemoryAddress

1000

1024

1016

1020

Variables inmemory

Memory

VariablesName

var1

pint

var2

Note that there is no guarantee that two variables are stored consecutively, even if they are defined consecutively.

Page 13: HKUST Summer Programming Course 2008

13

The Different Uses of Operator *

Do not confuse the use of dereference operator * versus the * as a part of a pointer type.

Example:int* p; // this means to declare a pointer variable

int i,j=10;

p = &j;

i = *p; // this means to dereference the variable p

Page 14: HKUST Summer Programming Course 2008

14

Pointer Assignments As with any variable, you may use a pointer variable on the right-

hand side of an assignment statement to assign its value to another address.

Example:

int main(){int x = 1;int *p1, *p2; // remember to add a * before p2p1 = &x; // address of x is assigned to p1p2 = p1; // content of p1 (which is address of

x) // is assigned to p2*p2 = 100;cout << "The address of x: " << p2 << “, x = ” << x << endl;return 0;

}

Page 15: HKUST Summer Programming Course 2008

15

Example on Pointers

int main (){int value1 = 5, value2 = 15; int *p1, *p2; // why not int* p1, p2?p1 = &value1; // p1 = address of value1p2 = &value2; // p2 = address of value2 *p1 = 10; // value pointed to by p1=10 *p2 = *p1; // value pointed to by p2= value

// pointed to by p1 p1 = p2; // p1 = p2 (pointer value copied) *p1 = 20; // value pointed to by p1 = 20 cout << "value1=" << value1 << “, value2=" << value2; return 0;

}

Output:

value1=10, value2=20

Page 16: HKUST Summer Programming Course 2008

16

Example – Swap Two Elements

void indirect_swap(char* ptr1, char* ptr2){char temp = *ptr1;*ptr1 = *ptr2;*ptr2 = temp;

}

int main() {char a = 'y';char b = 'n';indirect_swap(&a, &b);cout << a << “” << b << endl;return 0;

}

Page 17: HKUST Summer Programming Course 2008

17

Pointer Arithmetic

There are ONLY two arithmetic operations that you may use on pointers: Addition and Subtraction. Therefore, you can use +, -, ++, --, +=, -=. No multiplication nor division.

To understand what occurs in pointer arithmetic, let p1 be an integer pointer with current value of 2000. Also, assume integers are 4 bytes long. After the expression p1++, p1 contains 2004, NOT 2001.

The same is true of decrements. For example, assuming that p1 has the value 2000, the expression p1-- causes, p1 to have the value 1996.

Page 18: HKUST Summer Programming Course 2008

18

Pointer Arithmetic

Graphic representation of last example

200200

100100

300300

MemoryAddress

1996

2000

2004

Variables inmemory

Memory

VariablesName

p1--

p1++

20002000 p1

Page 19: HKUST Summer Programming Course 2008

19

Pointer Arithmetic

Generalizing from the preceding example, the following rules govern pointer arithmetic. Each time a pointer is incremented, it points to the memory

location of the next element of its base type. Each time a pointer is decremented, it points to the location

of the previous element. When applied to character pointers, this will appear as

“normal” arithmetic because characters are 1 byte long. All other pointers will increase or decrease by the length of

the data type they point to. Eg. The size of a double variable is 8 bytes.

Page 20: HKUST Summer Programming Course 2008

20

Pointer Arithmetic You are not limited to the increment and decrement the

pointer by one. For example, you may add or subtract integers to or from

pointers. The expression

p1 = p1 + 2;makes p1 point to the second element of p1’s type beyond the one it currently points to.

The expressionp1 = p1 - 2;makes p1 point to the second element of p1’s type precede the one it currently points to.

Page 21: HKUST Summer Programming Course 2008

21

Pointer Arithmetic

MemoryAddress

1996

2000

2004

Variables inmemory

Memory

VariablesName

p1-2

p1+2

20042004 p1

2008

2012

int* p1 = 2004;

Page 22: HKUST Summer Programming Course 2008

22

Pointer Comparisons

We can compare two pointers in a relational expression.

For instance, given two pointers, p and q, the following statements are perfectly valid.if(p < q)

cout << "p points to lower memory than q" << endl;

if(p > q)

cout << "p points to higher memory than q" << endl;

if(p == q)

cout << "p points to the same memory as q" << endl;

Page 23: HKUST Summer Programming Course 2008

23

Multiple Indirection (Pointer to Pointer)

You can have a pointer point to another pointer that

points to the target value. This is called “multiple indirection” or “pointer to pointer”.

Pointers to pointers can be confusing. The figure below helps clarify the concept of multiple indirection.

addressaddress valuevalue

Pointer variable Variable

addressaddress addressaddress

Pointer variable Pointer variable

valuevalue

Variable

SingleIndirection

MultipleIndirection

Page 24: HKUST Summer Programming Course 2008

24

Multiple Indirection (Pointer to Pointer)

The value of a normal pointer is the address of the object that contains the value.

In the case of pointer to pointer, the first pointer contains the address of second pointer, which points to the object that contains the value desired.

A variable that is a pointer to pointer can be declared as:

SYNTAX:<type>** <name>;

Example:int i = 10;int* ptr = &i;int** p_ptr = &ptr;int *q = ptr, **r = &ptr;

Page 25: HKUST Summer Programming Course 2008

25

Multiple Indirection (Pointer to Pointer)

Multiple indirection can be carried on to whatever extent required, but more than a pointer to a pointer is rarely needed.

In fact, excessive indirection is difficult to follow and prone to logical errors.

Page 26: HKUST Summer Programming Course 2008

26

Example – Multiple Indirection

int a = 80;

int *p = &a;

int **q = &p;

int ***r = &q;

cout << a << " ";

cout << *p << " ";

cout << **q << " ";

cout << ***r << " ";

MemoryAddress

2000

2004

2008

Variables inmemory

Memory

VariablesName

p

r

8080 a

2012

10001000

20002000

20042004

1000

q

Output:80 80 80 80

Page 27: HKUST Summer Programming Course 2008

27

Arrays and Pointers

There is a close relationship between pointers and arrays. An array name is actually a CONSTANT pointer to the first

element of the array. A constant pointer means we cannot change the value of the pointer variable (it cannot point to another location).

Example:int main (){

// Demonstrate array name is a constant pointerint a[5];cout << "Address of a[0]: " << &a[0] << endl << "Name as pointer: " << a << endl;return 0;

}

Output:Address of a[0]: 0x0065FDE4Name as pointer: 0x0065FDE4

Page 28: HKUST Summer Programming Course 2008

28

Problem

Can we do something like the following? int a = 10;

int* p = &a;

int A[6] = {0,2,4,8,10,12};

A = p; Can we do this? No! Since A is a constant pointer.

Page 29: HKUST Summer Programming Course 2008

29

Arrays and Pointers

// defines an array of integersint A[6] = {0,2,4,8,10,12};int* p;p = A; // p points to A[0];

Since array names and pointers are equivalent, we can also use p as the array name.

For examplep[3] = 7; or *(p+3) = 7;

is equivalent toA[3] = 7;

00

22

44

MemoryAddress

2000

2004

2008

Variables inmemory

Memory

VariablesName

A[0]

20002000 p

8 78 72012

10102016

A[1]

A[2]

A[3]

A[4]

12122020 A[5]

Page 30: HKUST Summer Programming Course 2008

30

Example - Arrays and Pointers

#include <iostream>

using namespace std;

int main(){

int A[6] = {2,4,6,8,10,22};

int *p = &A[1];

//int *p = A+1; // more efficient

cout << A[0] << " " << p[-1];

cout << " ";

cout << A[1] << " " << p[0];

return 0;

}

22

44

66

MemoryAddress

2000

2004

2008

Variables inmemory

Memory

VariablesName

A[0]

20042004 p

882012

10102016

A[1]

A[2]

A[3]

A[4]

22222020 A[5]

p[-1]

p[0]

Output:2 2 4 4

Page 31: HKUST Summer Programming Course 2008

31

Pass-by-Array (new slide) We can pass an array as a parameter into a function by two

methods.void func1( double array[ ], int size );void func2( double* array, int size );int main( ) {

double score[] = {1, 2.5, 6, 8.5};func1(score, 4);func2(score, 4);return 0;

} Both methods pass an array of type double into the function.

C++ passes in the address of the first element of the array. Hence, we should pass in the size, to indicate the end of the array.

Page 32: HKUST Summer Programming Course 2008

32

Pass-by-Array (new slide)

Indeed, there is no pass-by-array in C++. It is implemented by pass-by-value. But this time, it pass the

address (of the first element) by value. Even if you change the pointer array to point to another

array, the variable score is still pointing to the same array, without change (since it is pass-by-value).

However, you can directly modify the content of the array, which is pointed to by both pointers array and score. The modification to the content of the array can affect the

array score defined in the main function.

Page 33: HKUST Summer Programming Course 2008

33

Pass-by-Arrayvoid inputToArray( double* array, int size ) {

for (int i=0; i<size; i++) cin >> array[i];}void print( const double* array, int size ) {

for (int i=0; i<size; i++) cout << array[i] << endl;}int main( ) {

double score[10];inputToArray( score, 10 );print( score, 10 );return 0;

} This will reset the content of the array with the input from

keyboard and then print it to the screen. The keyword const will be covered in a minute.

Page 34: HKUST Summer Programming Course 2008

34

Character String Character string is indeed a character array.

Recall that “Hello World” is of the type const char[12] We can pass this into some function with parameter type const char*

Eg. char* strcpy(char* dest, const char* src) We can pass “Hello World” into the second parameter src, but not

dest. However, the following definitions are different:

char message1[12] = “Hello World”; “Hello World” is indeed a character array stored in a constant data

area (cannot be modified). message1 is a character array, initialized by “Hello World”. You can modify message1, say: message1[0] = ‘a’;

char* message2 = “Hello World”; message2 is simply a pointer, pointing to that constant data area. No separate array is allocated for storing “Hello World”. You cannot modify through this pointer, say: message2[0] = ‘a’;

Otherwise, runtime error will be resulted.

Page 35: HKUST Summer Programming Course 2008

35

Dereference Array Pointers

As array name is a constant pointer, dereference operator (*) can be used on it.

A[0] is same as *(A+0) A[1] is same as *(A+1) A[2] is same as *(A+2)

In general, A[n] is equivalent to *(A+n)

Page 36: HKUST Summer Programming Course 2008

36

Array of Pointers

Pointers may be arrayed like any other data type.

Example:int main(){

int a = 1, b = 2, c = 3;

// array of pointersint *p[3]; p[0] = &a;p[1] = &b;p[2] = &c;return 0;

}

11

22

33

MemoryAddress

2000

2004

2008

Variables inmemory

Memory

VariablesName

a

200020002012

200420042016

b

c

p[0]

p[1]

200820082020 p[2]

Page 37: HKUST Summer Programming Course 2008

37

Const and Pointer When using a pointer, two objects are involved: the pointer

itself, and the variable it is pointing to. The syntax for pointers to constants and constant pointers

can be confusing . The rule is that any const to the left of the * in a pointer type refers to the

object pointed to; any const to the right of the * refers to the pointer itself.

The above rules are valid if you are considering single indirection. It may be a little bit more complicated if multiple indirection is

considered. However, we won’t cover this in this course.

Page 38: HKUST Summer Programming Course 2008

38

Example1 - Const and Pointer char c = ‘Y’, d = ‘N’;

// constant pointer (must be initialized), cpc = &d is invalidchar *const cpc = &c;

// pointer to a constant char, *pcc = ‘H’ is invalidchar const* pcc = &c; const char* pcc2; // may not be initialized immediately

// constant pointer points to a constant char (must be// initialized), both cpcc = &d and *cpcc = ‘H’ are invalidconst char *const cpcc = &c; char const *const cpcc2 = &c;

Page 39: HKUST Summer Programming Course 2008

39

Example2 - Const and Pointerint main(){

char s[] = “Ming”; // type of “s” ~~ char *constchar p[] = “Adam”; // type of “p” ~~ char *constconst char* pcc = s; // Pointer to constant charpcc[0] = ‘5’; // Error!s[0] = ‘5’; // Fine!pcc = p; // OK, but what does that mean?

char *const cpc = s; // Constant pointercpc[0] = ‘5’; // OKcpc = p; // Error!

// Constant pointer to constant charconst char *const cpcc = s;cpcc[0] = ‘5’; // Error!cpcc = p; // Error!return 0;

}

Page 40: HKUST Summer Programming Course 2008

40

Example3 - Const and Pointer It is an error if you try to use a “pointer to non-const object” to

point to a “constant object”. Imagine that you can always modify the value indirectly through the

“pointer to non-const”. You may then modify a constant object through using a pointer to

point to it.

int m = 10; // normal objectconst int N = 100; // constant object

int* p = &m; // OKp = &N; // ERROR *p = 1000; // OKconst int* q = &N; // OK*q = 1000; // ERROR

Page 41: HKUST Summer Programming Course 2008

41

Example4 - Const and Pointer You cannot assign “pointer to const” to a “normal pointer”

Although it is valid to use a “pointer to const” to point to a non-constant object

To check which object (const or non-const) a pointer is pointing to need trace the code

C++ compiler won’t do this, so it simply disallow this type of assignment.

int i = 151;int* pi = &i; // pi is a “normal pointer”const int* pic = &i; // pic is a “pointer to const”pi = pic; // Error! Cannot convert from

// ‘const int*’ to `int *’,// although i is modifiable

Page 42: HKUST Summer Programming Course 2008

42

NULL Pointer A null pointer is a special pointer that is currently pointing

to nothing. Often pointers are set to zero (or predefined constant

NULL) to make them null pointers, or tested against zero (or NULL) to see if they are null.

Example:int* p = 0;if(p) // 0 (or null) is treated as false

cout << "p is not a null pointer" << endl;

int* p = NULL;if(p==NULL)

cout << "p is a null pointer" << endl;

Page 43: HKUST Summer Programming Course 2008

43

NULL Pointer

We will get an error if we try to dereference a NULL pointer.

Example#include <iostream>using namespace std;int main(){

int *p;p=NULL;cout << p << endl; // prints 0cout << &p << endl; // prints address of p cout << *p << endl; // Error!return 0;

}

Page 44: HKUST Summer Programming Course 2008

44

void Pointer Recall that int* can only point to a variable of type int. It

cannot point to a variable of type double. void pointer is a special pointer that can point to anything.

void pointer is of the type void* Note that void is not a datatype itself.

It can point to any datatype. Example:

int n = 10;double x = 1.2;int* p_n = &n;void* p = &n; // point to intvoid* p = &x; // point to doublevoid* p = &p_n; // point to an “integer pointer”

Page 45: HKUST Summer Programming Course 2008

45

void Pointer However, since void pointer can point to anything, the

length of its base type is unknown. We cannot use addition nor subtraction, whose result

depends on the length of its base type. Also, we cannot interpret the result what it is pointing to.

We cannot use dereference operator. We must first cast the void pointer to the “normal” pointer

before using the dereference operator.int n = 10;void* p_n = &n;cout << *((int*)p_n) << endl; // output 10cout << *((double*)p_n) << endl; // output

garbage

Page 46: HKUST Summer Programming Course 2008

46

void Pointer Recall that C++ is a strongly-typed programming language.

The advantage is that the compiler can detect many type mismatch errors.

void pointer prevent the compiler from checking the type. The compiler never knows whether casting a void pointer to

a “double pointer” (or an “integer pointer”) is valid or not. It is not recommended to use it in your programming.

However, some C-styled functions make use of the advantage of void pointer that it can point to anything. You may find that some standard functions may take a void

pointer as input. Some GUI programming also use void pointer.

However, this is far outside our scope.

Page 47: HKUST Summer Programming Course 2008

47Department of Computer Science and Engineering, HKUST

Pointers and References

Memory Allocation

Page 48: HKUST Summer Programming Course 2008

48

Memory Allocation

If we know prior to the execution of the program the amount of memory that we need, we can allocate memory statically prior to program start-up (i.e. compilation time). We call this static memory allocation.

However, we cannot always determine how much memory we need before our program runs. For example, the size of an array may not be known until

your executing program determines what these values should be.

So, what should we do?

We need dynamic memory allocation.

Page 49: HKUST Summer Programming Course 2008

49

Memory Allocation

In C++, we can request memory from operating system at runtime and we call this dynamic memory allocation. An area of memory called the heap (or free store) is available

in the run-time environment to handle dynamic memory allocation.

In C++ programs, we can use operator new to allocate memory from heap and operator delete to release heap memory.

Page 50: HKUST Summer Programming Course 2008

50

Conceptual View of Memory

Heap is a special area of memory which is reserved for dynamic variables.

MEMORYMEMORY

PROGRAM MEMORYPROGRAM MEMORY

DATA MEMORYDATA MEMORY

code for functionscode for functions

globalglobal program heap(dynamic memory)

program heap(dynamic memory) system stacksystem stack

Page 51: HKUST Summer Programming Course 2008

51

Memory Allocation Static Memory Allocation

Memory is allocated at compilation time. The following fragment allocates memory for x, y and p at compilation time.

int x, y; // x and y are integersint* p; // p is an integer pointer variable

Memory is returned automatically when variable/object goes out of scope. Dynamic Memory Allocation

Memory is allocated from heap at running time using new. Dynamic objects can exist beyond the function in which they were allocated. Memory is returned by a de-allocation request using delete.

Recall that statically allocated local variables are all put on the stack (activation record) The stack stores the pointer, which will be “released” automatically after the

activation record is popped out from the stack. The heap stores the newly-allocated object, which will not be automatically

released, even after the function returns.

Page 52: HKUST Summer Programming Course 2008

52

Dynamic Memory Allocation

SYNTAX:<name of type T*> = new <T>;

where T is the type of variable to allocate (e.g. int, char, double, user-defined type) and name is the name of the pointer variable.

The new operator allocates memory from heap and returns a pointer to it (or return its address value). Note that there is no identifier associated with the memory location

in heap. All you can do on it is through the usage of pointers. Pointer is very useful

If all the memory is used up and new is unable to allocate memory then new returns the value NULL.

Page 53: HKUST Summer Programming Course 2008

53

Stack Heap

Example - Dynamic Memory Allocation

int* p;p = new int;

// In a real programming situation, we should always// check for this memory allocation errorif(p == NULL){

cout << "Memory allocation is not successful" << endl;exit(1);

}

p Un-initializedint variable

Page 54: HKUST Summer Programming Course 2008

54

De-allocation of Memory

SYNTAX:

delete <name>;

where name is the name of the pointer variable that points

to dynamic memory.

The system has a limited amount of space on the heap. So as not to use it up, it is a good idea to return the USUSED dynamic memory to the heap, as soon as possible.

Page 55: HKUST Summer Programming Course 2008

55

Example – new and delete// Program to demonstrate new and deleteint main(){

int* p = new int; // allocate space from heapif(p == NULL){

cout << "Memory allocation is not successful" << endl;exit(1);

}*p = 100; // that space stores the value 100cout << "At " << p << " ";cout << "is the value " << *p << endl;delete p;// Note that it DOES NOT modify p. After executing delete p, // the value of p is still pointing to the old memory location.cout << p << endl;// It is a good practice to reset p to NULL after deletionp = NULL;return 0;

}

Page 56: HKUST Summer Programming Course 2008

56

Allocating and De-allocating Dynamic Arrays

The general forms of allocating dynamic array using new and delete are shown below.

SYNTAX:

<type>* <name> = new <type>[<size>];

delete [ ] <name>;

Here size specifies the number of elements in the array. Note that size does not have to be a constant. It can be an

expression evaluated at runtime. This is the key difference from static array.

The [ ] informs delete that an array is being released.

Page 57: HKUST Summer Programming Course 2008

57

Example – Dynamic Array

int main(){int* p;p = new int[10]; // allocate an array of 10 integersif(p == NULL){

cout << "Allocation is not successful" << endl;exit(1);

}for(int i=0; i<10; i++){

p[i] = i;cout << p[i] << " ";

}delete [] p; // release the arrayp = NULL;return 0;

}

Page 58: HKUST Summer Programming Course 2008

58

Example – Dynamic Array Need an array of unknown size

int main(){cout << "How many students? ";cin >> n;// The size of dynamic array is determined by user-inputint *grades = new int[n];for(int i=0; i<n; i++){

int mark;cout << "Input Mark for Student" << (i+1) <<

": ";cin >> mark;grades[i] = mark;

}for(int i=0; i<n; i++)

cout << grades[i] << " ";

delete[] grades;grades = NULL;return 0;

}

Page 59: HKUST Summer Programming Course 2008

59

Example – Dynamic Array Since static array is stored in the runtime stack, a very large

array cannot be fitted in this limited memory location, so we may need to use dynamic array even if we know the size of array in prior We usually allocate a small amount of memory for runtime stack

(say, 2MB) But the amount of memory you can allocated from heap depends on

the amount of physical memory (RAM) you have int main(){

const int N = 1000000;int *p = new int[N]; // an array of 1 million elementsfor(int i=0; i<N; i++)

p[i] = i;

delete [] p;p = NULL;return 0;

}

Page 60: HKUST Summer Programming Course 2008

60

Example - Dynamic 2D Array Allocation

int** table;table = new int*[4];

table[0]= new int[3];table[1]= new int[1];table[2]= new int[4];table[3]= new int[2];

table[0][0] = 1; table[0][1] = 2; table[0][2] = 3; table[1][0] = 4; table[2][0] = 5; table[2][1] = 6; table[2][2] = 7; table[2][3] = 8;table[3][0] = 9; table[3][1] = 10;

cout << "table[2][3]: " << table[2][3] << endl;

table[0]

table[1]

table[2]

table[3]

1 2 3

4

5 6 7 8

9 10

Output:Table[2][3]: 8

table

Page 61: HKUST Summer Programming Course 2008

61

Example - Dynamic 2D Array De-allocation

Each row must be deleted individually. Be careful to delete each row before deleting the pointer

table.

// Delete each individual row

for(int i=0; i<4; i++)

delete [] table[i];

// Delete the pointer table afterwards

delete [] table;

table = NULL;

Page 62: HKUST Summer Programming Course 2008

62

Illegal Deletion on Dynamic Arrays

p = new int[n] will allocate an array of n objects of type int and it will return a pointer to the start of the array.

delete [] p will destroy the array to which p points and return the memory to the heap.

p (in delete[ ] p) must point to the front of the dynamically allocated array. If it does not, the resulting computation will be unpredictable, i.e., it will depend upon what compiler you are using and what data you are inputting. You might get a run-time error, a wrong answer…

Page 63: HKUST Summer Programming Course 2008

63

Example – Illegal Delete// To demonstrate an illegal delete on dynamic arraysint main(){

int* A = new int[6];A[0] = 0; A[1] = 1; A[2] = 2;A[3] = 3; A[4] = 4; A[5] = 5;

int* p = A+2;cout << "A[1] = " << A[1] << endl;

// this is ILLEGAL! Result is unpredictable.delete [] p;

// the result depends upon the particular compilercout << "A[1] = " << A[1] << endl;return 0;

}

Page 64: HKUST Summer Programming Course 2008

64

Dangling Pointer

Dangling pointers are pointers which do not point to a valid object.

They arise when an object is deleted or de-allocated, without modifying the value of the pointer, so that the pointer still points to the memory location of the de-allocated memory.

For exampleint* p; // p is an integer pointer variable

int* q; // q is an integer pointer variable

p = new int; // allocate memory from heap

q = p;

Page 65: HKUST Summer Programming Course 2008

65

Dangling Pointer

The last example creates

But then executing

delete p;

p = NULL;

leaves q dangling.

*q = 10; // Illegal

p

q?

Location does notbelong to the program

p

q

Page 66: HKUST Summer Programming Course 2008

66

Memory Leakage A memory leak is what happens when we forgot to return a

block of memory allocated with the new operator or make it impossible to do so, e.g., losing all pointers to an allocated memory location. Recall that there is no identifier associated with the memory

location in the heap. When this happens, the memory can never be de-allocated

and is lost, i.e., never return to the heap. For example

int* p; // p is an integer pointer variableint* q; // q is an integer pointer variablep = new int; // allocate memory from heapq = new int;

Page 67: HKUST Summer Programming Course 2008

67

Memory Leakage

The last example creates

But then executing

q = p;

leaves the location previously pointed by q lost

p

q Location cannot beaccessed by the

program

p

q

Page 68: HKUST Summer Programming Course 2008

68

Problem of Memory Leakage

Memory leaks can seriously impact the ability of a program to complete its task.

It may be the case that subsequent dynamic memory requests cannot be satisfied because of insufficient of heap memory.

For this reason, memory leaks should be avoided. Write the delete statement in the same block as the new statement. Write the delete statement immediately after writing the new

statement. Except some special conditions, say:

A function used to allocating memory. In this case, add comment to explicitly ask the user of this function

to deallocate the resultant pointer after use.

Page 69: HKUST Summer Programming Course 2008

69Department of Computer Science and Engineering, HKUST

Pointers and References

References

Page 70: HKUST Summer Programming Course 2008

70

References

What are references? A reference is an alternative/another name (alias) for an

object. Reference variables are USUALLY USED in parameter

passing to functions.

SYNTAX:

// p is reference variable (an alternative name) of q

<type>& p = q; OR

<type> &p = q;qp

Page 71: HKUST Summer Programming Course 2008

71

Example

int j=1;// r is just another name of jint&r = j; // now r = j = 1int x = r; // now x = 1

// As r is just j, r changes to 2 means// j changes to 2 as wellr = 2; // now r = j = 2;j = 10; // now r = j = 10; A reference allows indirect manipulation of an object,

somewhat like a pointer, without requiring complicated pointer syntax .

Page 72: HKUST Summer Programming Course 2008

72

Important Points about Reference A reference MUST always bound to an object

(similar to a constant pointer). It must therefore be initialized when it is created.int j = 1;int& r1 = j; // okint& r2; // errors!

A reference cannot bound to another object once it initially was initialized to. But what does the following mean?int j = 10;int& r = j;int k = 50;r = k; // what does this mean?Assignment from a variable, say k, to a reference variable, say r,means r get assigned with the value of k.

Page 73: HKUST Summer Programming Course 2008

73

The Different Uses of Operator &

Do not confuse the use of operator & in declaring reference variable versus the use of & as the address of operator for pointer.

For exampleint j;

// this means to declare a reference variable

// “&” is a part of the reference type

int& i = j;

// this means the address of j to p

int* p = &j;

Page 74: HKUST Summer Programming Course 2008

74

Question

The following is wrong. Why?

int j;

int& i = &j;

The following is correct. What does it mean?int j;

int* p = &j;

int*& ref = p; // a reference of “integer pointer”

Page 75: HKUST Summer Programming Course 2008

75

Example - Reference

int main(){int j=1;// pi is an int* initialized to address of jint* pi = &j;// ref is a reference variable of type int*int*& ref = pi;cout << "j = " << j << endl;cout << "*pi = " << *pi << " *ref = " << *ref << endl;

int k=2;pi = &k;cout << "j = " << j << endl;cout << "*pi = " << *pi << " *ref = " << *ref << endl;return 0;

}

Page 76: HKUST Summer Programming Course 2008

76

Call by Reference

Reference arguments are special case of references variable.

For exampleint f(int& i){

++i;return i;

}int main(){

int j=7;cout << f(j) << endl;cout << j << endl;return 0;

}

Output:88

Page 77: HKUST Summer Programming Course 2008

77

Call by Reference

Variable i is a local variable in the function f. Its type is "int reference" and it is created when f is called.

In the call f(j), i is created similarly to the construction:

int& i = j; So within the function f, i will be an alias of the variable j,

and i cannot be bind to another variable. But every time the function is called, a new variable i is

created and it can be a reference to a different object.

Page 78: HKUST Summer Programming Course 2008

78

Why Call by Reference?

There are two reasons: The function caller wants the function to be able to change

the value of passed arguments. For efficiency: If you pass a function argument by value, the

function gets a local copy of the argument. For large objects, copying is expensive; on the other hand, passing an object by reference does not require copying, only passing a memory address (since reference is similar to pointer).

Page 79: HKUST Summer Programming Course 2008

79

Example – Call by Reference

void swap(char& y, char& z) {

char temp = y;

y = z;

z = temp;

}

int main() {

char a = 'y';

char b = 'n';

swap(a, b);

cout << a << b << endl;

return 0;

}

Page 80: HKUST Summer Programming Course 2008

80

const: References as Function Arguments

There are two good reasons to pass an argument as a reference, you can express your intention to leave a reference argument of your function unchanged by making it const. This has two advantages: First, if you accidentally try to modify the argument in your

function, the compiler will catch the error:void cbr(int& i){

i += 10; // Fine

}

void cbcr(const int& j){

j += 10; // Error!

}

Page 81: HKUST Summer Programming Course 2008

81

const: References as Function Arguments

Second, you can call a function that has a const reference parameter with both const and non-const arguments. Conversely, a function that has a non-const reference parameter can only be called with non-const arguments.

void cbr(int& i){ cout << i << endl; }void cbcr(const int& i){ cout << i << endl; }int main(){

int i = 50;const int j = 100;cbr(i);cbcr(i);cbr(j); // Errorcbcr(j);return 0;

}

Page 82: HKUST Summer Programming Course 2008

82

Pointer vs. Reference A reference can be thought of as a special kind of pointer,

but there are 3 big differences to remember! A pointer can point to nothing (NULL), but a reference is

always bound to an object. No need to check NULL when using reference

A pointer can point to different objects at different times (through assignments). A reference is always bound to the same object. Assignments to a reference do NOT change the object it

refers to but only the value of the referenced object. The name of a pointer refers to the pointer variable. The * or

-> (details of operator -> will be covered later) operators have to be used to access the object. The name of a reference always refers to the object. There are no special operators .

Page 83: HKUST Summer Programming Course 2008

83

Example – Pointers and References

void func1(int* pi){ (*pi)++; }void func2(int& ri){ ri++; }

int main(){int i=1;cout << "i = " << i << endl;// call using address of ifunc1(&i);cout << "i = " << i << endl;// call using ifunc2(i);cout << "i = " << i << endl;return 0;

}

Output:i = 1i = 2i = 3

Page 84: HKUST Summer Programming Course 2008

84

Return-by-Reference It is possible to define a function which returns a reference

variable (similar to returning a pointer).

double& at( double* array, int size, int index ) {return array[index];

}

int main( ) {double array[] = {12.3, 2.2, 3.4, 4.5, 4.3};at(array, 5, 2) = 12;cout << array[2] << endl; // output = 12return 0;

} More about this later when we are talking about operator

overloading.

Page 85: HKUST Summer Programming Course 2008

85

Return-by-Reference However, it is a pitfall to return the reference of a local

variable in the function. Recall that local variable is stored in activation record. Once

the function returns, the activation record will be destroyed and the variables inside cannot be used again. The returned reference cannot be modified (may lead to

runtime error). Printing the returned reference may result in garbage value.

double& at( double* array, int size, int index ) {double temp = array[index];return temp; // ERROR: returning reference

// of local variable}

Page 86: HKUST Summer Programming Course 2008

86

Return-by-Reference

Therefore, return-by-reference can be used in: Parameter passes into the function. Static variable of the function. Dynamically allocated items in the function. …

All these items won’t be destroyed after the function returns.

Similar rules apply on return-by-pointer.